2010-06-21 Atsushi Enomoto <atsushi@ximian.com>
[mcs.git] / mcs / method.cs
blob43d8f39f73fb7384c1a2cdfd5a4fa1fa8903cefc
1 //
2 // method.cs: Method based declarations
3 //
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 // Martin Baulig (martin@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004-2008 Novell, Inc
14 using System;
15 using System.Collections.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Runtime.CompilerServices;
19 using System.Runtime.InteropServices;
20 using System.Security;
21 using System.Security.Permissions;
22 using System.Text;
23 using System.Linq;
25 #if NET_2_1
26 using XmlElement = System.Object;
27 #else
28 using System.Xml;
29 #endif
31 using Mono.CompilerServices.SymbolWriter;
33 namespace Mono.CSharp {
35 public abstract class MethodCore : InterfaceMemberBase, IParametersMember
37 protected ParametersCompiled parameters;
38 protected ToplevelBlock block;
39 protected MethodSpec spec;
41 public MethodCore (DeclSpace parent, GenericMethod generic,
42 FullNamedExpression type, Modifiers mod, Modifiers allowed_mod,
43 MemberName name, Attributes attrs, ParametersCompiled parameters)
44 : base (parent, generic, type, mod, allowed_mod, name, attrs)
46 this.parameters = parameters;
50 // Returns the System.Type array for the parameters of this method
52 public TypeSpec [] ParameterTypes {
53 get {
54 return parameters.Types;
58 public ParametersCompiled ParameterInfo {
59 get {
60 return parameters;
64 AParametersCollection IParametersMember.Parameters {
65 get { return parameters; }
68 public ToplevelBlock Block {
69 get {
70 return block;
73 set {
74 block = value;
78 public CallingConventions CallingConventions {
79 get {
80 CallingConventions cc = parameters.CallingConvention;
81 if (!IsInterface)
82 if ((ModFlags & Modifiers.STATIC) == 0)
83 cc |= CallingConventions.HasThis;
85 // FIXME: How is `ExplicitThis' used in C#?
87 return cc;
91 protected override bool CheckOverrideAgainstBase (MemberSpec base_member)
93 bool res = base.CheckOverrideAgainstBase (base_member);
96 // Check that the permissions are not being changed
98 if (!CheckAccessModifiers (this, base_member)) {
99 Error_CannotChangeAccessModifiers (this, base_member);
100 res = false;
103 return res;
106 protected override bool CheckBase ()
108 // Check whether arguments were correct.
109 if (!DefineParameters (parameters))
110 return false;
112 return base.CheckBase ();
116 // Returns a string that represents the signature for this
117 // member which should be used in XML documentation.
119 public override string GetDocCommentName (DeclSpace ds)
121 return DocUtil.GetMethodDocCommentName (this, parameters, ds);
125 // Raised (and passed an XmlElement that contains the comment)
126 // when GenerateDocComment is writing documentation expectedly.
128 // FIXME: with a few effort, it could be done with XmlReader,
129 // that means removal of DOM use.
131 internal override void OnGenerateDocComment (XmlElement el)
133 DocUtil.OnMethodGenerateDocComment (this, el, Report);
137 // Represents header string for documentation comment.
139 public override string DocCommentHeader
141 get { return "M:"; }
144 public override bool EnableOverloadChecks (MemberCore overload)
146 if (overload is MethodCore) {
147 caching_flags |= Flags.MethodOverloadsExist;
148 return true;
151 if (overload is AbstractPropertyEventMethod)
152 return true;
154 return base.EnableOverloadChecks (overload);
157 public MethodSpec Spec {
158 get { return spec; }
161 protected override bool VerifyClsCompliance ()
163 if (!base.VerifyClsCompliance ())
164 return false;
166 if (parameters.HasArglist) {
167 Report.Warning (3000, 1, Location, "Methods with variable arguments are not CLS-compliant");
170 if (member_type != null && !member_type.IsCLSCompliant ()) {
171 Report.Warning (3002, 1, Location, "Return type of `{0}' is not CLS-compliant",
172 GetSignatureForError ());
175 parameters.VerifyClsCompliance (this);
176 return true;
180 public interface IGenericMethodDefinition : IMemberDefinition
182 TypeParameterSpec[] TypeParameters { get; }
183 int TypeParametersCount { get; }
185 // MethodInfo MakeGenericMethod (TypeSpec[] targs);
188 public class MethodSpec : MemberSpec, IParametersMember
190 MethodBase metaInfo;
191 AParametersCollection parameters;
192 TypeSpec returnType;
194 TypeSpec[] targs;
195 TypeParameterSpec[] constraints;
197 public MethodSpec (MemberKind kind, TypeSpec declaringType, IMemberDefinition details, TypeSpec returnType,
198 MethodBase info, AParametersCollection parameters, Modifiers modifiers)
199 : base (kind, declaringType, details, modifiers)
201 this.metaInfo = info;
202 this.parameters = parameters;
203 this.returnType = returnType;
206 #region Properties
208 public override int Arity {
209 get {
210 return IsGeneric ? GenericDefinition.TypeParametersCount : 0;
214 public TypeParameterSpec[] Constraints {
215 get {
216 if (constraints == null && IsGeneric)
217 constraints = GenericDefinition.TypeParameters;
219 return constraints;
223 public bool IsConstructor {
224 get {
225 return Kind == MemberKind.Constructor;
229 public IGenericMethodDefinition GenericDefinition {
230 get {
231 return (IGenericMethodDefinition) definition;
235 public bool IsExtensionMethod {
236 get {
237 return IsStatic && parameters.HasExtensionMethodType;
241 public bool IsSealed {
242 get {
243 return (Modifiers & Modifiers.SEALED) != 0;
247 // When is virtual or abstract
248 public bool IsVirtual {
249 get {
250 return (Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE)) != 0;
254 public bool IsReservedMethod {
255 get {
256 return Kind == MemberKind.Operator || IsAccessor;
260 TypeSpec IInterfaceMemberSpec.MemberType {
261 get {
262 return returnType;
266 public AParametersCollection Parameters {
267 get {
268 return parameters;
272 public TypeSpec ReturnType {
273 get {
274 return returnType;
278 public TypeSpec[] TypeArguments {
279 get {
280 return targs;
284 #endregion
286 public MethodSpec GetGenericMethodDefinition ()
288 if (!IsGeneric && !DeclaringType.IsGeneric)
289 return this;
291 return MemberCache.GetMember (declaringType, this);
294 public MethodBase GetMetaInfo ()
296 if ((state & StateFlags.PendingMetaInflate) != 0) {
297 if (DeclaringType.IsTypeBuilder) {
298 if (IsConstructor)
299 metaInfo = TypeBuilder.GetConstructor (DeclaringType.GetMetaInfo (), (ConstructorInfo) metaInfo);
300 else
301 metaInfo = TypeBuilder.GetMethod (DeclaringType.GetMetaInfo (), (MethodInfo) metaInfo);
302 } else {
303 metaInfo = MethodInfo.GetMethodFromHandle (metaInfo.MethodHandle, DeclaringType.GetMetaInfo ().TypeHandle);
306 state &= ~StateFlags.PendingMetaInflate;
309 if ((state & StateFlags.PendingMakeMethod) != 0) {
310 metaInfo = ((MethodInfo) metaInfo).MakeGenericMethod (targs.Select (l => l.GetMetaInfo ()).ToArray ());
311 state &= ~StateFlags.PendingMakeMethod;
314 return metaInfo;
317 public override string GetSignatureForError ()
319 string name;
320 if (IsConstructor) {
321 name = DeclaringType.GetSignatureForError () + "." + DeclaringType.Name;
322 } else if (Kind == MemberKind.Operator) {
323 var op = Operator.GetType (Name).Value;
324 if (op == Operator.OpType.Implicit || op == Operator.OpType.Explicit) {
325 name = DeclaringType.GetSignatureForError () + "." + Operator.GetName (op) + " operator " + returnType.GetSignatureForError ();
326 } else {
327 name = DeclaringType.GetSignatureForError () + ".operator " + Operator.GetName (op);
329 } else if (IsAccessor) {
330 int split = Name.IndexOf ('_');
331 name = Name.Substring (split + 1);
332 var postfix = Name.Substring (0, split);
333 if (split == 3) {
334 var pc = parameters.Count;
335 if (pc > 0 && postfix == "get") {
336 name = "this" + parameters.GetSignatureForError ("[", "]", pc);
337 } else if (pc > 1 && postfix == "set") {
338 name = "this" + parameters.GetSignatureForError ("[", "]", pc - 1);
342 return DeclaringType.GetSignatureForError () + "." + name + "." + postfix;
343 } else {
344 name = base.GetSignatureForError ();
345 if (targs != null)
346 name += "<" + TypeManager.CSharpName (targs) + ">";
347 else if (IsGeneric)
348 name += "<" + TypeManager.CSharpName (GenericDefinition.TypeParameters) + ">";
351 return name + parameters.GetSignatureForError ();
354 public override MemberSpec InflateMember (TypeParameterInflator inflator)
356 var ms = (MethodSpec) base.InflateMember (inflator);
357 ms.returnType = inflator.Inflate (returnType);
358 ms.parameters = parameters.Inflate (inflator);
359 if (IsGeneric)
360 ms.constraints = TypeParameterSpec.InflateConstraints (inflator, GenericDefinition.TypeParameters);
362 return ms;
365 public MethodSpec MakeGenericMethod (params TypeSpec[] targs)
367 if (targs == null)
368 throw new ArgumentNullException ();
369 // TODO MemberCache
370 // if (generic_intances != null && generic_intances.TryGetValue (targs, out ginstance))
371 // return ginstance;
373 //if (generic_intances == null)
374 // generic_intances = new Dictionary<TypeSpec[], Method> (TypeSpecArrayComparer.Default);
376 var inflator = new TypeParameterInflator (DeclaringType, GenericDefinition.TypeParameters, targs);
378 var inflated = (MethodSpec) MemberwiseClone ();
379 inflated.declaringType = inflator.TypeInstance;
380 inflated.returnType = inflator.Inflate (returnType);
381 inflated.parameters = parameters.Inflate (inflator);
382 inflated.targs = targs;
383 inflated.constraints = TypeParameterSpec.InflateConstraints (inflator, constraints ?? GenericDefinition.TypeParameters);
384 inflated.state |= StateFlags.PendingMakeMethod;
386 // if (inflated.parent == null)
387 // inflated.parent = parent;
389 //generic_intances.Add (targs, inflated);
390 return inflated;
393 public MethodSpec Mutate (TypeParameterMutator mutator)
395 var targs = TypeArguments;
396 if (targs != null)
397 targs = mutator.Mutate (targs);
399 var decl = DeclaringType;
400 if (DeclaringType.IsGenericOrParentIsGeneric) {
401 decl = mutator.Mutate (decl);
404 if (targs == TypeArguments && decl == DeclaringType)
405 return this;
407 var ms = (MethodSpec) MemberwiseClone ();
408 if (decl != DeclaringType) {
409 // Gets back MethodInfo in case of metaInfo was inflated
410 ms.metaInfo = MemberCache.GetMember (DeclaringType.GetDefinition (), this).metaInfo;
412 ms.declaringType = decl;
413 ms.state |= StateFlags.PendingMetaInflate;
416 if (targs != null) {
417 ms.targs = targs;
418 ms.state |= StateFlags.PendingMakeMethod;
421 return ms;
424 public void SetMetaInfo (MethodInfo info)
426 if (this.metaInfo != null)
427 throw new InternalErrorException ("MetaInfo reset");
429 this.metaInfo = info;
433 public abstract class MethodOrOperator : MethodCore, IMethodData
435 public MethodBuilder MethodBuilder;
436 ReturnParameter return_attributes;
437 Dictionary<SecurityAction, PermissionSet> declarative_security;
438 protected MethodData MethodData;
440 static string[] attribute_targets = new string [] { "method", "return" };
442 protected MethodOrOperator (DeclSpace parent, GenericMethod generic, FullNamedExpression type, Modifiers mod,
443 Modifiers allowed_mod, MemberName name,
444 Attributes attrs, ParametersCompiled parameters)
445 : base (parent, generic, type, mod, allowed_mod, name,
446 attrs, parameters)
450 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
452 if (a.Target == AttributeTargets.ReturnValue) {
453 if (return_attributes == null)
454 return_attributes = new ReturnParameter (this, MethodBuilder, Location);
456 return_attributes.ApplyAttributeBuilder (a, ctor, cdata, pa);
457 return;
460 if (a.IsInternalMethodImplAttribute) {
461 is_external_implementation = true;
464 if (a.Type == pa.DllImport) {
465 const Modifiers extern_static = Modifiers.EXTERN | Modifiers.STATIC;
466 if ((ModFlags & extern_static) != extern_static) {
467 Report.Error (601, a.Location, "The DllImport attribute must be specified on a method marked `static' and `extern'");
469 is_external_implementation = true;
472 if (a.IsValidSecurityAttribute ()) {
473 if (declarative_security == null)
474 declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
475 a.ExtractSecurityPermissionSet (declarative_security);
476 return;
479 if (MethodBuilder != null)
480 MethodBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
483 public override AttributeTargets AttributeTargets {
484 get {
485 return AttributeTargets.Method;
489 protected override bool CheckForDuplications ()
491 return Parent.MemberCache.CheckExistingMembersOverloads (this, parameters);
494 public virtual EmitContext CreateEmitContext (ILGenerator ig)
496 return new EmitContext (this, ig, MemberType);
499 public override bool Define ()
501 if (!base.Define ())
502 return false;
504 if (!CheckBase ())
505 return false;
507 MemberKind kind;
508 if (this is Operator)
509 kind = MemberKind.Operator;
510 else if (this is Destructor)
511 kind = MemberKind.Destructor;
512 else
513 kind = MemberKind.Method;
515 if (IsPartialDefinition) {
516 caching_flags &= ~Flags.Excluded_Undetected;
517 caching_flags |= Flags.Excluded;
519 // Add to member cache only when a partial method implementation has not been found yet
520 if ((caching_flags & Flags.PartialDefinitionExists) == 0) {
521 // MethodBase mb = new PartialMethodDefinitionInfo (this);
523 spec = new MethodSpec (kind, Parent.Definition, this, ReturnType, null, parameters, ModFlags);
524 Parent.MemberCache.AddMember (spec);
527 return true;
530 MethodData = new MethodData (
531 this, ModFlags, flags, this, MethodBuilder, GenericMethod, base_method);
533 if (!MethodData.Define (Parent.PartialContainer, GetFullName (MemberName), Report))
534 return false;
536 MethodBuilder = MethodData.MethodBuilder;
538 spec = new MethodSpec (kind, Parent.Definition, this, ReturnType, MethodBuilder, parameters, ModFlags);
539 if (MemberName.Arity > 0)
540 spec.IsGeneric = true;
542 Parent.MemberCache.AddMember (this, MethodBuilder.Name, spec);
544 return true;
547 protected override void DoMemberTypeIndependentChecks ()
549 base.DoMemberTypeIndependentChecks ();
551 CheckAbstractAndExtern (block != null);
553 if ((ModFlags & Modifiers.PARTIAL) != 0) {
554 for (int i = 0; i < parameters.Count; ++i) {
555 IParameterData p = parameters.FixedParameters [i];
556 if (p.ModFlags == Parameter.Modifier.OUT) {
557 Report.Error (752, Location, "`{0}': A partial method parameters cannot use `out' modifier",
558 GetSignatureForError ());
561 if (p.HasDefaultValue && IsPartialImplementation)
562 ((Parameter) p).Warning_UselessOptionalParameter (Report);
567 protected override void DoMemberTypeDependentChecks ()
569 base.DoMemberTypeDependentChecks ();
571 if (MemberType.IsStatic) {
572 Error_StaticReturnType ();
576 public override void Emit ()
578 if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
579 PredefinedAttributes.Get.CompilerGenerated.EmitAttribute (MethodBuilder);
580 if ((ModFlags & Modifiers.DEBUGGER_HIDDEN) != 0)
581 PredefinedAttributes.Get.DebuggerHidden.EmitAttribute (MethodBuilder);
583 if (ReturnType == InternalType.Dynamic) {
584 return_attributes = new ReturnParameter (this, MethodBuilder, Location);
585 PredefinedAttributes.Get.Dynamic.EmitAttribute (return_attributes.Builder);
586 } else {
587 var trans_flags = TypeManager.HasDynamicTypeUsed (ReturnType);
588 if (trans_flags != null) {
589 var pa = PredefinedAttributes.Get.DynamicTransform;
590 if (pa.Constructor != null || pa.ResolveConstructor (Location, ArrayContainer.MakeType (TypeManager.bool_type))) {
591 return_attributes = new ReturnParameter (this, MethodBuilder, Location);
592 return_attributes.Builder.SetCustomAttribute (
593 new CustomAttributeBuilder (pa.Constructor, new object [] { trans_flags }));
598 if (OptAttributes != null)
599 OptAttributes.Emit ();
601 if (declarative_security != null) {
602 foreach (var de in declarative_security) {
603 MethodBuilder.AddDeclarativeSecurity (de.Key, de.Value);
607 if (MethodData != null)
608 MethodData.Emit (Parent);
610 base.Emit ();
612 Block = null;
613 MethodData = null;
616 protected void Error_ConditionalAttributeIsNotValid ()
618 Report.Error (577, Location,
619 "Conditional not valid on `{0}' because it is a constructor, destructor, operator or explicit interface implementation",
620 GetSignatureForError ());
623 public bool IsPartialDefinition {
624 get {
625 return (ModFlags & Modifiers.PARTIAL) != 0 && Block == null;
629 public bool IsPartialImplementation {
630 get {
631 return (ModFlags & Modifiers.PARTIAL) != 0 && Block != null;
635 public override string[] ValidAttributeTargets {
636 get {
637 return attribute_targets;
641 #region IMethodData Members
643 public TypeSpec ReturnType {
644 get {
645 return MemberType;
649 public MemberName MethodName {
650 get {
651 return MemberName;
655 /// <summary>
656 /// Returns true if method has conditional attribute and the conditions is not defined (method is excluded).
657 /// </summary>
658 public override string[] ConditionalConditions ()
660 if ((caching_flags & (Flags.Excluded_Undetected | Flags.Excluded)) == 0)
661 return null;
663 if ((ModFlags & Modifiers.PARTIAL) != 0 && (caching_flags & Flags.Excluded) != 0)
664 return new string [0];
666 caching_flags &= ~Flags.Excluded_Undetected;
667 string[] conditions;
669 if (base_method == null) {
670 if (OptAttributes == null)
671 return null;
673 Attribute[] attrs = OptAttributes.SearchMulti (PredefinedAttributes.Get.Conditional);
674 if (attrs == null)
675 return null;
677 conditions = new string[attrs.Length];
678 for (int i = 0; i < conditions.Length; ++i)
679 conditions[i] = attrs[i].GetConditionalAttributeValue ();
680 } else {
681 conditions = base_method.MemberDefinition.ConditionalConditions();
684 if (conditions != null)
685 caching_flags |= Flags.Excluded;
687 return conditions;
690 GenericMethod IMethodData.GenericMethod {
691 get {
692 return GenericMethod;
696 public virtual void EmitExtraSymbolInfo (SourceMethod source)
699 #endregion
703 public class SourceMethod : IMethodDef
705 MethodBase method;
706 SourceMethodBuilder builder;
708 protected SourceMethod (DeclSpace parent, MethodBase method, ICompileUnit file)
710 this.method = method;
712 builder = SymbolWriter.OpenMethod (file, parent.NamespaceEntry.SymbolFileID, this);
715 public string Name {
716 get { return method.Name; }
719 public int Token {
720 get {
721 if (method is MethodBuilder)
722 return ((MethodBuilder) method).GetToken ().Token;
723 else if (method is ConstructorBuilder)
724 return ((ConstructorBuilder) method).GetToken ().Token;
725 else
726 throw new NotSupportedException ();
730 public void CloseMethod ()
732 SymbolWriter.CloseMethod ();
735 public void SetRealMethodName (string name)
737 if (builder != null)
738 builder.SetRealMethodName (name);
741 public static SourceMethod Create (DeclSpace parent, MethodBase method, Block block)
743 if (!SymbolWriter.HasSymbolWriter)
744 return null;
745 if (block == null)
746 return null;
748 Location start_loc = block.StartLocation;
749 if (start_loc.IsNull)
750 return null;
752 ICompileUnit compile_unit = start_loc.CompilationUnit;
753 if (compile_unit == null)
754 return null;
756 return new SourceMethod (parent, method, compile_unit);
760 public class Method : MethodOrOperator, IGenericMethodDefinition
762 /// <summary>
763 /// Modifiers allowed in a class declaration
764 /// </summary>
765 const Modifiers AllowedModifiers =
766 Modifiers.NEW |
767 Modifiers.PUBLIC |
768 Modifiers.PROTECTED |
769 Modifiers.INTERNAL |
770 Modifiers.PRIVATE |
771 Modifiers.STATIC |
772 Modifiers.VIRTUAL |
773 Modifiers.SEALED |
774 Modifiers.OVERRIDE |
775 Modifiers.ABSTRACT |
776 Modifiers.UNSAFE |
777 Modifiers.EXTERN;
779 const Modifiers AllowedInterfaceModifiers =
780 Modifiers.NEW | Modifiers.UNSAFE;
782 Method partialMethodImplementation;
784 public Method (DeclSpace parent, GenericMethod generic,
785 FullNamedExpression return_type, Modifiers mod,
786 MemberName name, ParametersCompiled parameters, Attributes attrs)
787 : base (parent, generic, return_type, mod,
788 parent.PartialContainer.Kind == MemberKind.Interface ? AllowedInterfaceModifiers : AllowedModifiers,
789 name, attrs, parameters)
793 protected Method (DeclSpace parent, FullNamedExpression return_type, Modifiers mod, Modifiers amod,
794 MemberName name, ParametersCompiled parameters, Attributes attrs)
795 : base (parent, null, return_type, mod, amod, name, attrs, parameters)
799 #region Properties
801 public override TypeParameter[] CurrentTypeParameters {
802 get {
803 if (GenericMethod != null)
804 return GenericMethod.CurrentTypeParameters;
806 return null;
810 public override bool HasUnresolvedConstraints {
811 get {
812 if (CurrentTypeParameters == null)
813 return false;
815 // When overriding base method constraints are fetched from
816 // base method but to find it we have to resolve parameters
817 // to find exact base method match
818 if (IsExplicitImpl || (ModFlags & Modifiers.OVERRIDE) != 0)
819 return base_method == null;
821 // Even for non-override generic method constraints check has to be
822 // delayed after all constraints are resolved
823 return true;
827 public TypeParameterSpec[] TypeParameters {
828 get {
829 return CurrentTypeParameters.Select (l => l.Type).ToArray ();
833 public int TypeParametersCount {
834 get {
835 return CurrentTypeParameters == null ? 0 : CurrentTypeParameters.Length;
839 #endregion
841 public override string GetSignatureForError()
843 return base.GetSignatureForError () + parameters.GetSignatureForError ();
846 void Error_DuplicateEntryPoint (Method b)
848 Report.Error (17, b.Location,
849 "Program `{0}' has more than one entry point defined: `{1}'",
850 CodeGen.FileName, b.GetSignatureForError ());
853 bool IsEntryPoint ()
855 if (ReturnType != TypeManager.void_type &&
856 ReturnType != TypeManager.int32_type)
857 return false;
859 if (parameters.IsEmpty)
860 return true;
862 if (parameters.Count > 1)
863 return false;
865 var ac = parameters.Types [0] as ArrayContainer;
866 return ac != null && ac.Rank == 1 && ac.Element == TypeManager.string_type &&
867 (parameters[0].ModFlags & ~Parameter.Modifier.PARAMS) == Parameter.Modifier.NONE;
870 public override FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
872 if (arity == 0) {
873 TypeParameter[] tp = CurrentTypeParameters;
874 if (tp != null) {
875 TypeParameter t = TypeParameter.FindTypeParameter (tp, name);
876 if (t != null)
877 return new TypeParameterExpr (t, loc);
881 return base.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
884 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
886 if (a.Type == pa.Conditional) {
887 if (IsExplicitImpl) {
888 Error_ConditionalAttributeIsNotValid ();
889 return;
892 if (ReturnType != TypeManager.void_type) {
893 Report.Error (578, Location, "Conditional not valid on `{0}' because its return type is not void", GetSignatureForError ());
894 return;
897 if ((ModFlags & Modifiers.OVERRIDE) != 0) {
898 Report.Error (243, Location, "Conditional not valid on `{0}' because it is an override method", GetSignatureForError ());
899 return;
902 if (IsInterface) {
903 Report.Error (582, Location, "Conditional not valid on interface members");
904 return;
907 if (MethodData.implementing != null) {
908 Report.SymbolRelatedToPreviousError (MethodData.implementing.DeclaringType);
909 Report.Error (629, Location, "Conditional member `{0}' cannot implement interface member `{1}'",
910 GetSignatureForError (), TypeManager.CSharpSignature (MethodData.implementing));
911 return;
914 for (int i = 0; i < parameters.Count; ++i) {
915 if (parameters.FixedParameters [i].ModFlags == Parameter.Modifier.OUT) {
916 Report.Error (685, Location, "Conditional method `{0}' cannot have an out parameter", GetSignatureForError ());
917 return;
922 if (a.Type == pa.Extension) {
923 a.Error_MisusedExtensionAttribute ();
924 return;
927 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
930 protected virtual void DefineTypeParameters ()
932 var tparams = CurrentTypeParameters;
934 TypeParameterSpec[] base_tparams = null;
935 TypeParameterSpec[] base_decl_tparams = TypeParameterSpec.EmptyTypes;
936 TypeSpec[] base_targs = TypeSpec.EmptyTypes;
937 if (((ModFlags & Modifiers.OVERRIDE) != 0 || IsExplicitImpl)) {
938 if (base_method != null) {
939 base_tparams = base_method.GenericDefinition.TypeParameters;
940 if (base_method.DeclaringType.IsGeneric) {
941 base_decl_tparams = base_method.DeclaringType.MemberDefinition.TypeParameters;
942 base_targs = Parent.BaseType.TypeArguments;
944 } else if (MethodData.implementing != null) {
945 base_tparams = MethodData.implementing.GenericDefinition.TypeParameters;
946 if (MethodData.implementing.DeclaringType.IsGeneric) {
947 base_decl_tparams = MethodData.implementing.DeclaringType.MemberDefinition.TypeParameters;
948 foreach (var iface in Parent.CurrentType.Interfaces) {
949 if (iface == MethodData.implementing.DeclaringType) {
950 base_targs = iface.TypeArguments;
951 break;
958 for (int i = 0; i < tparams.Length; ++i) {
959 var tp = tparams[i];
961 if (!tp.ResolveConstraints (this))
962 continue;
965 // Copy base constraints for override/explicit methods
967 if (base_tparams != null) {
968 var base_tparam = base_tparams[i];
969 tp.Type.SpecialConstraint = base_tparam.SpecialConstraint;
971 var inflator = new TypeParameterInflator (CurrentType, base_decl_tparams, base_targs);
972 base_tparam.InflateConstraints (inflator, tp.Type);
973 } else if (MethodData.implementing != null) {
974 var base_tp = MethodData.implementing.Constraints[i];
975 if (!tp.Type.HasSameConstraintsImplementation (base_tp)) {
976 Report.SymbolRelatedToPreviousError (MethodData.implementing);
977 Report.Error (425, Location,
978 "The constraints for type parameter `{0}' of method `{1}' must match the constraints for type parameter `{2}' of interface method `{3}'. Consider using an explicit interface implementation instead",
979 tp.GetSignatureForError (), GetSignatureForError (), base_tp.GetSignatureForError (), MethodData.implementing.GetSignatureForError ());
986 // Creates the type
988 public override bool Define ()
990 if (type_expr.Type == TypeManager.void_type && parameters.IsEmpty && MemberName.Arity == 0 && MemberName.Name == Destructor.MetadataName) {
991 Report.Warning (465, 1, Location, "Introducing `Finalize' method can interfere with destructor invocation. Did you intend to declare a destructor?");
994 if (!base.Define ())
995 return false;
997 if (partialMethodImplementation != null && IsPartialDefinition)
998 MethodBuilder = partialMethodImplementation.MethodBuilder;
1000 if (RootContext.StdLib && TypeManager.IsSpecialType (ReturnType)) {
1001 Error1599 (Location, ReturnType, Report);
1002 return false;
1005 if (CurrentTypeParameters == null) {
1006 if (base_method != null) {
1007 if (parameters.Count == 1 && ParameterTypes[0] == TypeManager.object_type && Name == "Equals")
1008 Parent.PartialContainer.Mark_HasEquals ();
1009 else if (parameters.IsEmpty && Name == "GetHashCode")
1010 Parent.PartialContainer.Mark_HasGetHashCode ();
1013 } else {
1014 DefineTypeParameters ();
1017 if (block != null && block.IsIterator && !(Parent is IteratorStorey)) {
1019 // Current method is turned into automatically generated
1020 // wrapper which creates an instance of iterator
1022 Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags, Compiler);
1023 ModFlags |= Modifiers.DEBUGGER_HIDDEN;
1026 if ((ModFlags & Modifiers.STATIC) == 0)
1027 return true;
1029 if (parameters.HasExtensionMethodType) {
1030 if (Parent.PartialContainer.IsStatic && !Parent.IsGeneric) {
1031 if (!Parent.IsTopLevel)
1032 Report.Error (1109, Location, "`{0}': Extension methods cannot be defined in a nested class",
1033 GetSignatureForError ());
1035 PredefinedAttribute pa = PredefinedAttributes.Get.Extension;
1036 if (!pa.IsDefined) {
1037 Report.Error (1110, Location,
1038 "`{0}': Extension methods cannot be declared without a reference to System.Core.dll assembly. Add the assembly reference or remove `this' modifer from the first parameter",
1039 GetSignatureForError ());
1042 ModFlags |= Modifiers.METHOD_EXTENSION;
1043 Parent.PartialContainer.ModFlags |= Modifiers.METHOD_EXTENSION;
1044 Spec.DeclaringType.SetExtensionMethodContainer ();
1045 CodeGen.Assembly.HasExtensionMethods = true;
1046 } else {
1047 Report.Error (1106, Location, "`{0}': Extension methods must be defined in a non-generic static class",
1048 GetSignatureForError ());
1053 // This is used to track the Entry Point,
1055 if (RootContext.NeedsEntryPoint &&
1056 Name == "Main" &&
1057 (RootContext.MainClass == null ||
1058 RootContext.MainClass == Parent.TypeBuilder.FullName)){
1059 if (IsEntryPoint ()) {
1061 if (RootContext.EntryPoint == null) {
1062 if (Parent.IsGeneric || MemberName.IsGeneric) {
1063 Report.Warning (402, 4, Location, "`{0}': an entry point cannot be generic or in a generic type",
1064 GetSignatureForError ());
1065 } else {
1066 SetIsUsed ();
1067 RootContext.EntryPoint = this;
1069 } else {
1070 Error_DuplicateEntryPoint (RootContext.EntryPoint);
1071 Error_DuplicateEntryPoint (this);
1073 } else {
1074 Report.Warning (28, 4, Location, "`{0}' has the wrong signature to be an entry point",
1075 GetSignatureForError ());
1079 return true;
1083 // Emits the code
1085 public override void Emit ()
1087 try {
1088 Report.Debug (64, "METHOD EMIT", this, MethodBuilder, Location, Block, MethodData);
1089 if (IsPartialDefinition) {
1091 // Use partial method implementation builder for partial method declaration attributes
1093 if (partialMethodImplementation != null) {
1094 MethodBuilder = partialMethodImplementation.MethodBuilder;
1095 return;
1097 } else if ((ModFlags & Modifiers.PARTIAL) != 0 && (caching_flags & Flags.PartialDefinitionExists) == 0) {
1098 Report.Error (759, Location, "A partial method `{0}' implementation is missing a partial method declaration",
1099 GetSignatureForError ());
1102 if (CurrentTypeParameters != null) {
1103 var ge = type_expr as GenericTypeExpr;
1104 if (ge != null)
1105 ge.CheckConstraints (this);
1107 foreach (Parameter p in parameters.FixedParameters) {
1108 ge = p.TypeExpression as GenericTypeExpr;
1109 if (ge != null)
1110 ge.CheckConstraints (this);
1113 for (int i = 0; i < CurrentTypeParameters.Length; ++i) {
1114 var tp = CurrentTypeParameters [i];
1115 tp.CheckGenericConstraints ();
1116 tp.Emit ();
1120 base.Emit ();
1122 if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
1123 PredefinedAttributes.Get.Extension.EmitAttribute (MethodBuilder);
1124 } catch {
1125 Console.WriteLine ("Internal compiler error at {0}: exception caught while emitting {1}",
1126 Location, MethodBuilder);
1127 throw;
1131 public override bool EnableOverloadChecks (MemberCore overload)
1133 // TODO: It can be deleted when members will be defined in correct order
1134 if (overload is Operator)
1135 return overload.EnableOverloadChecks (this);
1137 if (overload is Indexer)
1138 return false;
1140 return base.EnableOverloadChecks (overload);
1143 public static void Error1599 (Location loc, TypeSpec t, Report Report)
1145 Report.Error (1599, loc, "Method or delegate cannot return type `{0}'", TypeManager.CSharpName (t));
1148 protected override bool ResolveMemberType ()
1150 if (GenericMethod != null) {
1151 MethodBuilder = Parent.TypeBuilder.DefineMethod (GetFullName (MemberName), flags);
1152 if (!GenericMethod.Define (this))
1153 return false;
1156 return base.ResolveMemberType ();
1159 public void SetPartialDefinition (Method methodDefinition)
1161 caching_flags |= Flags.PartialDefinitionExists;
1162 methodDefinition.partialMethodImplementation = this;
1164 // Ensure we are always using method declaration parameters
1165 for (int i = 0; i < methodDefinition.parameters.Count; ++i ) {
1166 parameters [i].Name = methodDefinition.parameters [i].Name;
1167 parameters [i].DefaultValue = methodDefinition.parameters [i].DefaultValue;
1170 if (methodDefinition.attributes == null)
1171 return;
1173 if (attributes == null) {
1174 attributes = methodDefinition.attributes;
1175 } else {
1176 attributes.Attrs.AddRange (methodDefinition.attributes.Attrs);
1181 public abstract class ConstructorInitializer : ExpressionStatement
1183 Arguments argument_list;
1184 MethodGroupExpr base_constructor_group;
1186 public ConstructorInitializer (Arguments argument_list, Location loc)
1188 this.argument_list = argument_list;
1189 this.loc = loc;
1192 public Arguments Arguments {
1193 get {
1194 return argument_list;
1198 public override Expression CreateExpressionTree (ResolveContext ec)
1200 throw new NotSupportedException ("ET");
1203 protected override Expression DoResolve (ResolveContext ec)
1205 eclass = ExprClass.Value;
1207 // FIXME: Hack
1208 var caller_builder = (Constructor) ec.MemberContext;
1210 if (argument_list != null) {
1211 bool dynamic;
1214 // Spec mandates that constructor initializer will not have `this' access
1216 using (ec.Set (ResolveContext.Options.BaseInitializer)) {
1217 argument_list.Resolve (ec, out dynamic);
1220 if (dynamic) {
1221 ec.Report.Error (1975, loc,
1222 "The constructor call cannot be dynamically dispatched within constructor initializer");
1224 return null;
1228 type = ec.CurrentType;
1229 if (this is ConstructorBaseInitializer) {
1230 if (ec.CurrentType.BaseType == null)
1231 return this;
1233 type = ec.CurrentType.BaseType;
1234 if (ec.CurrentType.IsStruct) {
1235 ec.Report.Error (522, loc,
1236 "`{0}': Struct constructors cannot call base constructors", caller_builder.GetSignatureForError ());
1237 return this;
1239 } else {
1241 // It is legal to have "this" initializers that take no arguments
1242 // in structs, they are just no-ops.
1244 // struct D { public D (int a) : this () {}
1246 if (TypeManager.IsStruct (ec.CurrentType) && argument_list == null)
1247 return this;
1250 base_constructor_group = MemberLookupFinal (
1251 ec, null, type, ConstructorBuilder.ConstructorName, 0, MemberKind.Constructor,
1252 BindingRestriction.AccessibleOnly | BindingRestriction.DeclaredOnly,
1253 loc) as MethodGroupExpr;
1255 if (base_constructor_group == null)
1256 return this;
1258 base_constructor_group = base_constructor_group.OverloadResolve (
1259 ec, ref argument_list, false, loc);
1261 if (base_constructor_group == null)
1262 return this;
1264 if (!ec.IsStatic)
1265 base_constructor_group.InstanceExpression = ec.GetThis (loc);
1267 var base_ctor = base_constructor_group.BestCandidate;
1269 // TODO MemberCache: Does it work for inflated types ?
1270 if (base_ctor == caller_builder.Spec){
1271 ec.Report.Error (516, loc, "Constructor `{0}' cannot call itself",
1272 caller_builder.GetSignatureForError ());
1275 return this;
1278 public override void Emit (EmitContext ec)
1280 // It can be null for static initializers
1281 if (base_constructor_group == null)
1282 return;
1284 ec.Mark (loc);
1286 base_constructor_group.EmitCall (ec, argument_list);
1289 public override void EmitStatement (EmitContext ec)
1291 Emit (ec);
1295 public class ConstructorBaseInitializer : ConstructorInitializer {
1296 public ConstructorBaseInitializer (Arguments argument_list, Location l) :
1297 base (argument_list, l)
1302 class GeneratedBaseInitializer: ConstructorBaseInitializer {
1303 public GeneratedBaseInitializer (Location loc):
1304 base (null, loc)
1309 public class ConstructorThisInitializer : ConstructorInitializer {
1310 public ConstructorThisInitializer (Arguments argument_list, Location l) :
1311 base (argument_list, l)
1316 public class Constructor : MethodCore, IMethodData {
1317 public ConstructorBuilder ConstructorBuilder;
1318 public ConstructorInitializer Initializer;
1319 Dictionary<SecurityAction, PermissionSet> declarative_security;
1320 bool has_compliant_args;
1322 // <summary>
1323 // Modifiers allowed for a constructor.
1324 // </summary>
1325 public const Modifiers AllowedModifiers =
1326 Modifiers.PUBLIC |
1327 Modifiers.PROTECTED |
1328 Modifiers.INTERNAL |
1329 Modifiers.STATIC |
1330 Modifiers.UNSAFE |
1331 Modifiers.EXTERN |
1332 Modifiers.PRIVATE;
1334 static readonly string[] attribute_targets = new string [] { "method" };
1337 // The spec claims that static is not permitted, but
1338 // my very own code has static constructors.
1340 public Constructor (DeclSpace parent, string name, Modifiers mod, Attributes attrs, ParametersCompiled args,
1341 ConstructorInitializer init, Location loc)
1342 : base (parent, null, null, mod, AllowedModifiers,
1343 new MemberName (name, loc), attrs, args)
1345 Initializer = init;
1348 public bool HasCompliantArgs {
1349 get { return has_compliant_args; }
1352 public override AttributeTargets AttributeTargets {
1353 get { return AttributeTargets.Constructor; }
1357 // Returns true if this is a default constructor
1359 public bool IsDefault ()
1361 if ((ModFlags & Modifiers.STATIC) != 0)
1362 return parameters.IsEmpty;
1364 return parameters.IsEmpty &&
1365 (Initializer is ConstructorBaseInitializer) &&
1366 (Initializer.Arguments == null);
1369 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1371 if (a.IsValidSecurityAttribute ()) {
1372 if (declarative_security == null) {
1373 declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
1375 a.ExtractSecurityPermissionSet (declarative_security);
1376 return;
1379 if (a.IsInternalMethodImplAttribute) {
1380 is_external_implementation = true;
1383 ConstructorBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
1386 protected override bool CheckBase ()
1388 if ((ModFlags & Modifiers.STATIC) != 0) {
1389 if (!parameters.IsEmpty) {
1390 Report.Error (132, Location, "`{0}': The static constructor must be parameterless",
1391 GetSignatureForError ());
1392 return false;
1395 // the rest can be ignored
1396 return true;
1399 // Check whether arguments were correct.
1400 if (!DefineParameters (parameters))
1401 return false;
1403 if ((caching_flags & Flags.MethodOverloadsExist) != 0)
1404 Parent.MemberCache.CheckExistingMembersOverloads (this, parameters);
1406 if (Parent.PartialContainer.Kind == MemberKind.Struct && parameters.IsEmpty) {
1407 Report.Error (568, Location,
1408 "Structs cannot contain explicit parameterless constructors");
1409 return false;
1412 CheckProtectedModifier ();
1414 return true;
1418 // Creates the ConstructorBuilder
1420 public override bool Define ()
1422 if (ConstructorBuilder != null)
1423 return true;
1425 var ca = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName;
1427 if ((ModFlags & Modifiers.STATIC) != 0) {
1428 ca |= MethodAttributes.Static | MethodAttributes.Private;
1429 } else {
1430 ca |= ModifiersExtensions.MethodAttr (ModFlags);
1433 if (!CheckAbstractAndExtern (block != null))
1434 return false;
1436 // Check if arguments were correct.
1437 if (!CheckBase ())
1438 return false;
1440 ConstructorBuilder = Parent.TypeBuilder.DefineConstructor (
1441 ca, CallingConventions,
1442 parameters.GetMetaInfo ());
1444 spec = new MethodSpec (MemberKind.Constructor, Parent.Definition, this, TypeManager.void_type, ConstructorBuilder, parameters, ModFlags);
1446 Parent.MemberCache.AddMember (spec);
1448 // It's here only to report an error
1449 if (block != null && block.IsIterator) {
1450 member_type = TypeManager.void_type;
1451 Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags, Compiler);
1454 return true;
1458 // Emits the code
1460 public override void Emit ()
1462 if (Parent.PartialContainer.IsComImport) {
1463 if (!IsDefault ()) {
1464 Report.Error (669, Location, "`{0}': A class with the ComImport attribute cannot have a user-defined constructor",
1465 Parent.GetSignatureForError ());
1467 ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.InternalCall);
1470 if ((ModFlags & Modifiers.DEBUGGER_HIDDEN) != 0)
1471 PredefinedAttributes.Get.DebuggerHidden.EmitAttribute (ConstructorBuilder);
1473 if (OptAttributes != null)
1474 OptAttributes.Emit ();
1476 base.Emit ();
1479 // If we use a "this (...)" constructor initializer, then
1480 // do not emit field initializers, they are initialized in the other constructor
1482 bool emit_field_initializers = ((ModFlags & Modifiers.STATIC) != 0) ||
1483 !(Initializer is ConstructorThisInitializer);
1485 BlockContext bc = new BlockContext (this, block, TypeManager.void_type);
1486 bc.Set (ResolveContext.Options.ConstructorScope);
1488 if (emit_field_initializers)
1489 Parent.PartialContainer.ResolveFieldInitializers (bc);
1491 if (block != null) {
1492 // If this is a non-static `struct' constructor and doesn't have any
1493 // initializer, it must initialize all of the struct's fields.
1494 if ((Parent.PartialContainer.Kind == MemberKind.Struct) &&
1495 ((ModFlags & Modifiers.STATIC) == 0) && (Initializer == null))
1496 block.AddThisVariable (Parent, Location);
1498 if (block != null && (ModFlags & Modifiers.STATIC) == 0){
1499 if (Parent.PartialContainer.Kind == MemberKind.Class && Initializer == null)
1500 Initializer = new GeneratedBaseInitializer (Location);
1502 if (Initializer != null) {
1503 block.AddScopeStatement (new StatementExpression (Initializer));
1508 parameters.ApplyAttributes (ConstructorBuilder);
1510 SourceMethod source = SourceMethod.Create (Parent, ConstructorBuilder, block);
1512 if (block != null) {
1513 if (block.Resolve (null, bc, parameters, this)) {
1514 EmitContext ec = new EmitContext (this, ConstructorBuilder.GetILGenerator (), bc.ReturnType);
1515 ec.With (EmitContext.Options.ConstructorScope, true);
1517 if (!ec.HasReturnLabel && bc.HasReturnLabel) {
1518 ec.ReturnLabel = bc.ReturnLabel;
1519 ec.HasReturnLabel = true;
1522 block.Emit (ec);
1526 if (source != null)
1527 source.CloseMethod ();
1529 if (declarative_security != null) {
1530 foreach (var de in declarative_security) {
1531 ConstructorBuilder.AddDeclarativeSecurity (de.Key, de.Value);
1535 block = null;
1538 protected override MemberSpec FindBaseMember (out MemberSpec bestCandidate)
1540 // Is never override
1541 bestCandidate = null;
1542 return null;
1545 public override string GetSignatureForError()
1547 return base.GetSignatureForError () + parameters.GetSignatureForError ();
1550 public override string[] ValidAttributeTargets {
1551 get {
1552 return attribute_targets;
1556 protected override bool VerifyClsCompliance ()
1558 if (!base.VerifyClsCompliance () || !IsExposedFromAssembly ()) {
1559 return false;
1562 if (!parameters.IsEmpty && Parent.Definition.IsAttribute) {
1563 foreach (TypeSpec param in parameters.Types) {
1564 if (param.IsArray) {
1565 return true;
1570 has_compliant_args = true;
1571 return true;
1574 #region IMethodData Members
1576 public MemberName MethodName {
1577 get {
1578 return MemberName;
1582 public TypeSpec ReturnType {
1583 get {
1584 return MemberType;
1588 public EmitContext CreateEmitContext (ILGenerator ig)
1590 throw new NotImplementedException ();
1593 public bool IsExcluded()
1595 return false;
1598 GenericMethod IMethodData.GenericMethod {
1599 get {
1600 return null;
1604 void IMethodData.EmitExtraSymbolInfo (SourceMethod source)
1607 #endregion
1610 /// <summary>
1611 /// Interface for MethodData class. Holds links to parent members to avoid member duplication.
1612 /// </summary>
1613 public interface IMethodData
1615 CallingConventions CallingConventions { get; }
1616 Location Location { get; }
1617 MemberName MethodName { get; }
1618 TypeSpec ReturnType { get; }
1619 GenericMethod GenericMethod { get; }
1620 ParametersCompiled ParameterInfo { get; }
1621 MethodSpec Spec { get; }
1623 Attributes OptAttributes { get; }
1624 ToplevelBlock Block { get; set; }
1626 EmitContext CreateEmitContext (ILGenerator ig);
1627 string GetSignatureForError ();
1628 void EmitExtraSymbolInfo (SourceMethod source);
1632 // Encapsulates most of the Method's state
1634 public class MethodData {
1635 static FieldInfo methodbuilder_attrs_field;
1636 public readonly IMethodData method;
1638 public readonly GenericMethod GenericMethod;
1641 // Are we implementing an interface ?
1643 public MethodSpec implementing;
1646 // Protected data.
1648 protected InterfaceMemberBase member;
1649 protected Modifiers modifiers;
1650 protected MethodAttributes flags;
1651 protected TypeSpec declaring_type;
1652 protected MethodSpec parent_method;
1654 MethodBuilder builder;
1655 public MethodBuilder MethodBuilder {
1656 get {
1657 return builder;
1661 public TypeSpec DeclaringType {
1662 get {
1663 return declaring_type;
1667 public MethodData (InterfaceMemberBase member,
1668 Modifiers modifiers, MethodAttributes flags, IMethodData method)
1670 this.member = member;
1671 this.modifiers = modifiers;
1672 this.flags = flags;
1674 this.method = method;
1677 public MethodData (InterfaceMemberBase member,
1678 Modifiers modifiers, MethodAttributes flags,
1679 IMethodData method, MethodBuilder builder,
1680 GenericMethod generic, MethodSpec parent_method)
1681 : this (member, modifiers, flags, method)
1683 this.builder = builder;
1684 this.GenericMethod = generic;
1685 this.parent_method = parent_method;
1688 public bool Define (DeclSpace parent, string method_full_name, Report Report)
1690 TypeContainer container = parent.PartialContainer;
1692 PendingImplementation pending = container.PendingImplementations;
1693 if (pending != null){
1694 implementing = pending.IsInterfaceMethod (method.MethodName, member.InterfaceType, this);
1696 if (member.InterfaceType != null){
1697 if (implementing == null){
1698 if (member is PropertyBase) {
1699 Report.Error (550, method.Location, "`{0}' is an accessor not found in interface member `{1}{2}'",
1700 method.GetSignatureForError (), TypeManager.CSharpName (member.InterfaceType),
1701 member.GetSignatureForError ().Substring (member.GetSignatureForError ().LastIndexOf ('.')));
1703 } else {
1704 Report.Error (539, method.Location,
1705 "`{0}.{1}' in explicit interface declaration is not a member of interface",
1706 TypeManager.CSharpName (member.InterfaceType), member.ShortName);
1708 return false;
1710 if (implementing.IsAccessor && !(method is AbstractPropertyEventMethod)) {
1711 Report.SymbolRelatedToPreviousError (implementing);
1712 Report.Error (683, method.Location, "`{0}' explicit method implementation cannot implement `{1}' because it is an accessor",
1713 member.GetSignatureForError (), TypeManager.CSharpSignature (implementing));
1714 return false;
1716 } else {
1717 if (implementing != null) {
1718 AbstractPropertyEventMethod prop_method = method as AbstractPropertyEventMethod;
1719 if (prop_method == null) {
1720 if (implementing.IsAccessor) {
1721 Report.SymbolRelatedToPreviousError (implementing);
1722 Report.Error (470, method.Location, "Method `{0}' cannot implement interface accessor `{1}'",
1723 method.GetSignatureForError (), TypeManager.CSharpSignature (implementing));
1725 } else if (implementing.DeclaringType.IsInterface) {
1726 if (!implementing.IsAccessor) {
1727 Report.SymbolRelatedToPreviousError (implementing);
1728 Report.Error (686, method.Location, "Accessor `{0}' cannot implement interface member `{1}' for type `{2}'. Use an explicit interface implementation",
1729 method.GetSignatureForError (), TypeManager.CSharpSignature (implementing), container.GetSignatureForError ());
1730 } else {
1731 PropertyBase.PropertyMethod pm = prop_method as PropertyBase.PropertyMethod;
1732 if (pm != null && pm.HasCustomAccessModifier && (pm.ModFlags & Modifiers.PUBLIC) == 0) {
1733 Report.SymbolRelatedToPreviousError (implementing);
1734 Report.Error (277, method.Location, "Accessor `{0}' must be declared public to implement interface member `{1}'",
1735 method.GetSignatureForError (), implementing.GetSignatureForError ());
1744 // For implicit implementations, make sure we are public, for
1745 // explicit implementations, make sure we are private.
1747 if (implementing != null){
1749 // Setting null inside this block will trigger a more
1750 // verbose error reporting for missing interface implementations
1752 // The "candidate" function has been flagged already
1753 // but it wont get cleared
1755 if (member.IsExplicitImpl){
1756 if (method.ParameterInfo.HasParams && !implementing.Parameters.HasParams) {
1757 Report.SymbolRelatedToPreviousError (implementing);
1758 Report.Error (466, method.Location, "`{0}': the explicit interface implementation cannot introduce the params modifier",
1759 method.GetSignatureForError ());
1761 } else {
1762 if (implementing.DeclaringType.IsInterface) {
1764 // If this is an interface method implementation,
1765 // check for public accessibility
1767 if ((flags & MethodAttributes.MemberAccessMask) != MethodAttributes.Public)
1769 implementing = null;
1771 } else if ((flags & MethodAttributes.MemberAccessMask) == MethodAttributes.Private){
1772 // We may never be private.
1773 implementing = null;
1775 } else if ((modifiers & Modifiers.OVERRIDE) == 0){
1777 // We may be protected if we're overriding something.
1779 implementing = null;
1784 // Static is not allowed
1786 if ((modifiers & Modifiers.STATIC) != 0){
1787 implementing = null;
1792 // If implementing is still valid, set flags
1794 if (implementing != null){
1796 // When implementing interface methods, set NewSlot
1797 // unless, we are overwriting a method.
1799 if (implementing.DeclaringType.IsInterface){
1800 if ((modifiers & Modifiers.OVERRIDE) == 0)
1801 flags |= MethodAttributes.NewSlot;
1804 flags |= MethodAttributes.Virtual | MethodAttributes.HideBySig;
1806 // Set Final unless we're virtual, abstract or already overriding a method.
1807 if ((modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE)) == 0)
1808 flags |= MethodAttributes.Final;
1811 // clear the pending implementation flag (requires explicit methods to be defined first)
1813 parent.PartialContainer.PendingImplementations.ImplementMethod (method.MethodName,
1814 member.InterfaceType, this, member.IsExplicitImpl);
1817 // Update indexer accessor name to match implementing abstract accessor
1819 if (!implementing.DeclaringType.IsInterface && !member.IsExplicitImpl && implementing.IsAccessor)
1820 method_full_name = implementing.MemberDefinition.Name;
1823 DefineMethodBuilder (container, method_full_name, method.ParameterInfo);
1825 if (builder == null)
1826 return false;
1828 // if (container.CurrentType != null)
1829 // declaring_type = container.CurrentType;
1830 // else
1831 declaring_type = container.Definition;
1833 if (implementing != null && member.IsExplicitImpl) {
1834 container.TypeBuilder.DefineMethodOverride (builder, (MethodInfo) implementing.GetMetaInfo ());
1837 return true;
1841 /// <summary>
1842 /// Create the MethodBuilder for the method
1843 /// </summary>
1844 void DefineMethodBuilder (TypeContainer container, string method_name, ParametersCompiled param)
1846 var return_type = method.ReturnType.GetMetaInfo ();
1847 var p_types = param.GetMetaInfo ();
1849 if (builder == null) {
1850 builder = container.TypeBuilder.DefineMethod (
1851 method_name, flags, method.CallingConventions,
1852 return_type, p_types);
1853 return;
1857 // Generic method has been already defined to resolve method parameters
1858 // correctly when they use type parameters
1860 builder.SetParameters (p_types);
1861 builder.SetReturnType (return_type);
1862 if (builder.Attributes != flags) {
1863 try {
1864 if (methodbuilder_attrs_field == null)
1865 methodbuilder_attrs_field = typeof (MethodBuilder).GetField ("attrs", BindingFlags.NonPublic | BindingFlags.Instance);
1866 methodbuilder_attrs_field.SetValue (builder, flags);
1867 } catch {
1868 container.Compiler.Report.RuntimeMissingSupport (method.Location, "Generic method MethodAttributes");
1874 // Emits the code
1876 public void Emit (DeclSpace parent)
1878 if (GenericMethod != null)
1879 GenericMethod.EmitAttributes ();
1881 method.ParameterInfo.ApplyAttributes (MethodBuilder);
1883 SourceMethod source = SourceMethod.Create (parent, MethodBuilder, method.Block);
1885 ToplevelBlock block = method.Block;
1886 if (block != null) {
1887 BlockContext bc = new BlockContext ((IMemberContext) method, block, method.ReturnType);
1888 if (block.Resolve (null, bc, method.ParameterInfo, method)) {
1889 EmitContext ec = method.CreateEmitContext (MethodBuilder.GetILGenerator ());
1890 if (!ec.HasReturnLabel && bc.HasReturnLabel) {
1891 ec.ReturnLabel = bc.ReturnLabel;
1892 ec.HasReturnLabel = true;
1895 block.Emit (ec);
1899 if (source != null) {
1900 method.EmitExtraSymbolInfo (source);
1901 source.CloseMethod ();
1906 public class Destructor : MethodOrOperator
1908 const Modifiers AllowedModifiers =
1909 Modifiers.UNSAFE |
1910 Modifiers.EXTERN;
1912 static readonly string[] attribute_targets = new string [] { "method" };
1914 public static readonly string MetadataName = "Finalize";
1916 public Destructor (DeclSpace parent, Modifiers mod, ParametersCompiled parameters, Attributes attrs, Location l)
1917 : base (parent, null, null, mod, AllowedModifiers,
1918 new MemberName (MetadataName, l), attrs, parameters)
1920 ModFlags &= ~Modifiers.PRIVATE;
1921 ModFlags |= Modifiers.PROTECTED | Modifiers.OVERRIDE;
1924 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1926 if (a.Type == pa.Conditional) {
1927 Error_ConditionalAttributeIsNotValid ();
1928 return;
1931 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
1934 protected override bool CheckBase ()
1936 // Don't check base, destructors have special syntax
1937 return true;
1940 public override void Emit()
1942 var base_type = Parent.PartialContainer.BaseType;
1943 if (base_type != null && Block != null) {
1944 MethodGroupExpr method_expr = Expression.MethodLookup (Parent.Module.Compiler, Parent.Definition, base_type, MemberKind.Destructor, MetadataName, 0, Location);
1945 if (method_expr == null)
1946 throw new NotImplementedException ();
1948 method_expr.QueriedBaseType = base_type;
1949 method_expr.InstanceExpression = new CompilerGeneratedThis (Parent.Definition, Location);
1951 ToplevelBlock new_block = new ToplevelBlock (Compiler, Block.StartLocation);
1952 new_block.EndLocation = Block.EndLocation;
1954 Block finaly_block = new ExplicitBlock (new_block, Location, Location);
1955 Block try_block = new Block (new_block, block);
1958 // 0-size arguments to avoid CS0250 error
1959 // TODO: Should use AddScopeStatement or something else which emits correct
1960 // debugger scope
1962 finaly_block.AddStatement (new StatementExpression (new Invocation (method_expr, new Arguments (0))));
1963 new_block.AddStatement (new TryFinally (try_block, finaly_block, Location));
1965 block = new_block;
1968 base.Emit ();
1971 public override string GetSignatureForError ()
1973 return Parent.GetSignatureForError () + ".~" + Parent.MemberName.Name + "()";
1976 protected override bool ResolveMemberType ()
1978 member_type = TypeManager.void_type;
1979 return true;
1982 public override string[] ValidAttributeTargets {
1983 get {
1984 return attribute_targets;
1989 // Ooouh Martin, templates are missing here.
1990 // When it will be possible move here a lot of child code and template method type.
1991 public abstract class AbstractPropertyEventMethod : MemberCore, IMethodData {
1992 protected MethodData method_data;
1993 protected ToplevelBlock block;
1994 protected Dictionary<SecurityAction, PermissionSet> declarative_security;
1996 protected readonly string prefix;
1998 ReturnParameter return_attributes;
2000 public AbstractPropertyEventMethod (InterfaceMemberBase member, string prefix, Attributes attrs, Location loc)
2001 : base (member.Parent, SetupName (prefix, member, loc), attrs)
2003 this.prefix = prefix;
2006 static MemberName SetupName (string prefix, InterfaceMemberBase member, Location loc)
2008 return new MemberName (member.MemberName.Left, prefix + member.ShortName, loc);
2011 public void UpdateName (InterfaceMemberBase member)
2013 SetMemberName (SetupName (prefix, member, Location));
2016 #region IMethodData Members
2018 public ToplevelBlock Block {
2019 get {
2020 return block;
2023 set {
2024 block = value;
2028 public CallingConventions CallingConventions {
2029 get {
2030 return CallingConventions.Standard;
2034 public EmitContext CreateEmitContext (ILGenerator ig)
2036 return new EmitContext (this, ig, ReturnType);
2039 public bool IsExcluded ()
2041 return false;
2044 GenericMethod IMethodData.GenericMethod {
2045 get {
2046 return null;
2050 public MemberName MethodName {
2051 get {
2052 return MemberName;
2056 public TypeSpec[] ParameterTypes {
2057 get {
2058 return ParameterInfo.Types;
2062 public abstract ParametersCompiled ParameterInfo { get ; }
2063 public abstract TypeSpec ReturnType { get; }
2065 #endregion
2067 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
2069 if (a.Type == pa.CLSCompliant || a.Type == pa.Obsolete || a.Type == pa.Conditional) {
2070 Report.Error (1667, a.Location,
2071 "Attribute `{0}' is not valid on property or event accessors. It is valid on `{1}' declarations only",
2072 TypeManager.CSharpName (a.Type), a.GetValidTargets ());
2073 return;
2076 if (a.IsValidSecurityAttribute ()) {
2077 if (declarative_security == null)
2078 declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
2079 a.ExtractSecurityPermissionSet (declarative_security);
2080 return;
2083 if (a.Target == AttributeTargets.Method) {
2084 method_data.MethodBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
2085 return;
2088 if (a.Target == AttributeTargets.ReturnValue) {
2089 if (return_attributes == null)
2090 return_attributes = new ReturnParameter (this, method_data.MethodBuilder, Location);
2092 return_attributes.ApplyAttributeBuilder (a, ctor, cdata, pa);
2093 return;
2096 ApplyToExtraTarget (a, ctor, cdata, pa);
2099 protected virtual void ApplyToExtraTarget (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
2101 throw new NotSupportedException ("You forgot to define special attribute target handling");
2104 // It is not supported for the accessors
2105 public sealed override bool Define()
2107 throw new NotSupportedException ();
2110 public virtual void Emit (DeclSpace parent)
2112 method_data.Emit (parent);
2114 if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
2115 PredefinedAttributes.Get.CompilerGenerated.EmitAttribute (method_data.MethodBuilder);
2116 if (((ModFlags & Modifiers.DEBUGGER_HIDDEN) != 0))
2117 PredefinedAttributes.Get.DebuggerHidden.EmitAttribute (method_data.MethodBuilder);
2119 if (ReturnType == InternalType.Dynamic) {
2120 return_attributes = new ReturnParameter (this, method_data.MethodBuilder, Location);
2121 PredefinedAttributes.Get.Dynamic.EmitAttribute (return_attributes.Builder);
2122 } else {
2123 var trans_flags = TypeManager.HasDynamicTypeUsed (ReturnType);
2124 if (trans_flags != null) {
2125 var pa = PredefinedAttributes.Get.DynamicTransform;
2126 if (pa.Constructor != null || pa.ResolveConstructor (Location, ArrayContainer.MakeType (TypeManager.bool_type))) {
2127 return_attributes = new ReturnParameter (this, method_data.MethodBuilder, Location);
2128 return_attributes.Builder.SetCustomAttribute (
2129 new CustomAttributeBuilder (pa.Constructor, new object [] { trans_flags }));
2134 if (OptAttributes != null)
2135 OptAttributes.Emit ();
2137 if (declarative_security != null) {
2138 foreach (var de in declarative_security) {
2139 method_data.MethodBuilder.AddDeclarativeSecurity (de.Key, de.Value);
2143 block = null;
2146 public override bool EnableOverloadChecks (MemberCore overload)
2148 if (overload is MethodCore) {
2149 caching_flags |= Flags.MethodOverloadsExist;
2150 return true;
2153 // This can only happen with indexers and it will
2154 // be catched as indexer difference
2155 if (overload is AbstractPropertyEventMethod)
2156 return true;
2158 return false;
2161 public override bool IsClsComplianceRequired()
2163 return false;
2166 public MethodSpec Spec { get; protected set; }
2169 // Represents header string for documentation comment.
2171 public override string DocCommentHeader {
2172 get { throw new InvalidOperationException ("Unexpected attempt to get doc comment from " + this.GetType () + "."); }
2175 void IMethodData.EmitExtraSymbolInfo (SourceMethod source)
2179 public class Operator : MethodOrOperator {
2181 const Modifiers AllowedModifiers =
2182 Modifiers.PUBLIC |
2183 Modifiers.UNSAFE |
2184 Modifiers.EXTERN |
2185 Modifiers.STATIC;
2187 public enum OpType : byte {
2189 // Unary operators
2190 LogicalNot,
2191 OnesComplement,
2192 Increment,
2193 Decrement,
2194 True,
2195 False,
2197 // Unary and Binary operators
2198 Addition,
2199 Subtraction,
2201 UnaryPlus,
2202 UnaryNegation,
2204 // Binary operators
2205 Multiply,
2206 Division,
2207 Modulus,
2208 BitwiseAnd,
2209 BitwiseOr,
2210 ExclusiveOr,
2211 LeftShift,
2212 RightShift,
2213 Equality,
2214 Inequality,
2215 GreaterThan,
2216 LessThan,
2217 GreaterThanOrEqual,
2218 LessThanOrEqual,
2220 // Implicit and Explicit
2221 Implicit,
2222 Explicit,
2224 // Just because of enum
2228 public readonly OpType OperatorType;
2230 static readonly string [] [] names;
2232 static Operator ()
2234 names = new string[(int)OpType.TOP][];
2235 names [(int) OpType.LogicalNot] = new string [] { "!", "op_LogicalNot" };
2236 names [(int) OpType.OnesComplement] = new string [] { "~", "op_OnesComplement" };
2237 names [(int) OpType.Increment] = new string [] { "++", "op_Increment" };
2238 names [(int) OpType.Decrement] = new string [] { "--", "op_Decrement" };
2239 names [(int) OpType.True] = new string [] { "true", "op_True" };
2240 names [(int) OpType.False] = new string [] { "false", "op_False" };
2241 names [(int) OpType.Addition] = new string [] { "+", "op_Addition" };
2242 names [(int) OpType.Subtraction] = new string [] { "-", "op_Subtraction" };
2243 names [(int) OpType.UnaryPlus] = new string [] { "+", "op_UnaryPlus" };
2244 names [(int) OpType.UnaryNegation] = new string [] { "-", "op_UnaryNegation" };
2245 names [(int) OpType.Multiply] = new string [] { "*", "op_Multiply" };
2246 names [(int) OpType.Division] = new string [] { "/", "op_Division" };
2247 names [(int) OpType.Modulus] = new string [] { "%", "op_Modulus" };
2248 names [(int) OpType.BitwiseAnd] = new string [] { "&", "op_BitwiseAnd" };
2249 names [(int) OpType.BitwiseOr] = new string [] { "|", "op_BitwiseOr" };
2250 names [(int) OpType.ExclusiveOr] = new string [] { "^", "op_ExclusiveOr" };
2251 names [(int) OpType.LeftShift] = new string [] { "<<", "op_LeftShift" };
2252 names [(int) OpType.RightShift] = new string [] { ">>", "op_RightShift" };
2253 names [(int) OpType.Equality] = new string [] { "==", "op_Equality" };
2254 names [(int) OpType.Inequality] = new string [] { "!=", "op_Inequality" };
2255 names [(int) OpType.GreaterThan] = new string [] { ">", "op_GreaterThan" };
2256 names [(int) OpType.LessThan] = new string [] { "<", "op_LessThan" };
2257 names [(int) OpType.GreaterThanOrEqual] = new string [] { ">=", "op_GreaterThanOrEqual" };
2258 names [(int) OpType.LessThanOrEqual] = new string [] { "<=", "op_LessThanOrEqual" };
2259 names [(int) OpType.Implicit] = new string [] { "implicit", "op_Implicit" };
2260 names [(int) OpType.Explicit] = new string [] { "explicit", "op_Explicit" };
2263 public Operator (DeclSpace parent, OpType type, FullNamedExpression ret_type,
2264 Modifiers mod_flags, ParametersCompiled parameters,
2265 ToplevelBlock block, Attributes attrs, Location loc)
2266 : base (parent, null, ret_type, mod_flags, AllowedModifiers,
2267 new MemberName (GetMetadataName (type), loc), attrs, parameters)
2269 OperatorType = type;
2270 Block = block;
2273 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
2275 if (a.Type == pa.Conditional) {
2276 Error_ConditionalAttributeIsNotValid ();
2277 return;
2280 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
2283 public override bool Define ()
2285 const Modifiers RequiredModifiers = Modifiers.PUBLIC | Modifiers.STATIC;
2286 if ((ModFlags & RequiredModifiers) != RequiredModifiers){
2287 Report.Error (558, Location, "User-defined operator `{0}' must be declared static and public", GetSignatureForError ());
2290 if (!base.Define ())
2291 return false;
2293 if (block != null && block.IsIterator && !(Parent is IteratorStorey)) {
2295 // Current method is turned into automatically generated
2296 // wrapper which creates an instance of iterator
2298 Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags, Compiler);
2299 ModFlags |= Modifiers.DEBUGGER_HIDDEN;
2302 // imlicit and explicit operator of same types are not allowed
2303 if (OperatorType == OpType.Explicit)
2304 Parent.MemberCache.CheckExistingMembersOverloads (this, GetMetadataName (OpType.Implicit), parameters);
2305 else if (OperatorType == OpType.Implicit)
2306 Parent.MemberCache.CheckExistingMembersOverloads (this, GetMetadataName (OpType.Explicit), parameters);
2308 TypeSpec declaring_type = Parent.CurrentType;
2309 TypeSpec return_type = MemberType;
2310 TypeSpec first_arg_type = ParameterTypes [0];
2312 TypeSpec first_arg_type_unwrap = first_arg_type;
2313 if (TypeManager.IsNullableType (first_arg_type))
2314 first_arg_type_unwrap = TypeManager.GetTypeArguments (first_arg_type) [0];
2316 TypeSpec return_type_unwrap = return_type;
2317 if (TypeManager.IsNullableType (return_type))
2318 return_type_unwrap = TypeManager.GetTypeArguments (return_type) [0];
2321 // Rules for conversion operators
2323 if (OperatorType == OpType.Implicit || OperatorType == OpType.Explicit) {
2324 if (first_arg_type_unwrap == return_type_unwrap && first_arg_type_unwrap == declaring_type) {
2325 Report.Error (555, Location,
2326 "User-defined operator cannot take an object of the enclosing type and convert to an object of the enclosing type");
2327 return false;
2330 TypeSpec conv_type;
2331 if (TypeManager.IsEqual (declaring_type, return_type) || declaring_type == return_type_unwrap) {
2332 conv_type = first_arg_type;
2333 } else if (TypeManager.IsEqual (declaring_type, first_arg_type) || declaring_type == first_arg_type_unwrap) {
2334 conv_type = return_type;
2335 } else {
2336 Report.Error (556, Location,
2337 "User-defined conversion must convert to or from the enclosing type");
2338 return false;
2341 if (conv_type == InternalType.Dynamic) {
2342 Report.Error (1964, Location,
2343 "User-defined conversion `{0}' cannot convert to or from the dynamic type",
2344 GetSignatureForError ());
2346 return false;
2349 if (conv_type.IsInterface) {
2350 Report.Error (552, Location, "User-defined conversion `{0}' cannot convert to or from an interface type",
2351 GetSignatureForError ());
2352 return false;
2355 if (conv_type.IsClass) {
2356 if (TypeManager.IsSubclassOf (declaring_type, conv_type)) {
2357 Report.Error (553, Location, "User-defined conversion `{0}' cannot convert to or from a base class",
2358 GetSignatureForError ());
2359 return false;
2362 if (TypeManager.IsSubclassOf (conv_type, declaring_type)) {
2363 Report.Error (554, Location, "User-defined conversion `{0}' cannot convert to or from a derived class",
2364 GetSignatureForError ());
2365 return false;
2368 } else if (OperatorType == OpType.LeftShift || OperatorType == OpType.RightShift) {
2369 if (first_arg_type != declaring_type || parameters.Types[1] != TypeManager.int32_type) {
2370 Report.Error (564, Location, "Overloaded shift operator must have the type of the first operand be the containing type, and the type of the second operand must be int");
2371 return false;
2373 } else if (parameters.Count == 1) {
2374 // Checks for Unary operators
2376 if (OperatorType == OpType.Increment || OperatorType == OpType.Decrement) {
2377 if (return_type != declaring_type && !TypeManager.IsSubclassOf (return_type, declaring_type)) {
2378 Report.Error (448, Location,
2379 "The return type for ++ or -- operator must be the containing type or derived from the containing type");
2380 return false;
2382 if (first_arg_type != declaring_type) {
2383 Report.Error (
2384 559, Location, "The parameter type for ++ or -- operator must be the containing type");
2385 return false;
2389 if (!TypeManager.IsEqual (first_arg_type_unwrap, declaring_type)) {
2390 Report.Error (562, Location,
2391 "The parameter type of a unary operator must be the containing type");
2392 return false;
2395 if (OperatorType == OpType.True || OperatorType == OpType.False) {
2396 if (return_type != TypeManager.bool_type) {
2397 Report.Error (
2398 215, Location,
2399 "The return type of operator True or False " +
2400 "must be bool");
2401 return false;
2405 } else if (!TypeManager.IsEqual (first_arg_type_unwrap, declaring_type)) {
2406 // Checks for Binary operators
2408 var second_arg_type = ParameterTypes[1];
2409 if (TypeManager.IsNullableType (second_arg_type))
2410 second_arg_type = TypeManager.GetTypeArguments (second_arg_type)[0];
2412 if (!TypeManager.IsEqual (second_arg_type, declaring_type)) {
2413 Report.Error (563, Location,
2414 "One of the parameters of a binary operator must be the containing type");
2415 return false;
2419 return true;
2422 protected override bool ResolveMemberType ()
2424 if (!base.ResolveMemberType ())
2425 return false;
2427 flags |= MethodAttributes.SpecialName | MethodAttributes.HideBySig;
2428 return true;
2431 protected override MemberSpec FindBaseMember (out MemberSpec bestCandidate)
2433 // Operator cannot be override
2434 bestCandidate = null;
2435 return null;
2438 public static string GetName (OpType ot)
2440 return names [(int) ot] [0];
2443 public static string GetName (string metadata_name)
2445 for (int i = 0; i < names.Length; ++i) {
2446 if (names [i] [1] == metadata_name)
2447 return names [i] [0];
2449 return null;
2452 public static string GetMetadataName (OpType ot)
2454 return names [(int) ot] [1];
2457 public static string GetMetadataName (string name)
2459 for (int i = 0; i < names.Length; ++i) {
2460 if (names [i] [0] == name)
2461 return names [i] [1];
2463 return null;
2466 public static OpType? GetType (string metadata_name)
2468 for (int i = 0; i < names.Length; ++i) {
2469 if (names[i][1] == metadata_name)
2470 return (OpType) i;
2473 return null;
2476 public OpType GetMatchingOperator ()
2478 switch (OperatorType) {
2479 case OpType.Equality:
2480 return OpType.Inequality;
2481 case OpType.Inequality:
2482 return OpType.Equality;
2483 case OpType.True:
2484 return OpType.False;
2485 case OpType.False:
2486 return OpType.True;
2487 case OpType.GreaterThan:
2488 return OpType.LessThan;
2489 case OpType.LessThan:
2490 return OpType.GreaterThan;
2491 case OpType.GreaterThanOrEqual:
2492 return OpType.LessThanOrEqual;
2493 case OpType.LessThanOrEqual:
2494 return OpType.GreaterThanOrEqual;
2495 default:
2496 return OpType.TOP;
2500 public override string GetSignatureForError ()
2502 StringBuilder sb = new StringBuilder ();
2503 if (OperatorType == OpType.Implicit || OperatorType == OpType.Explicit) {
2504 sb.AppendFormat ("{0}.{1} operator {2}",
2505 Parent.GetSignatureForError (), GetName (OperatorType), type_expr.GetSignatureForError ());
2507 else {
2508 sb.AppendFormat ("{0}.operator {1}", Parent.GetSignatureForError (), GetName (OperatorType));
2511 sb.Append (parameters.GetSignatureForError ());
2512 return sb.ToString ();