[mcs] Inflate constraints of compiler generated proxy base call methods. Fixes #52294
[mono-project.git] / mcs / mcs / method.cs
blob2f42ebbaa0bf4edfee3cc39c0f0e80d7a0de6cf9
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
12 // Copyright 2011 Xamarin Inc.
15 using System;
16 using System.Collections.Generic;
17 using System.Security;
18 using System.Security.Permissions;
19 using System.Text;
20 using System.Linq;
21 using Mono.CompilerServices.SymbolWriter;
22 using System.Runtime.CompilerServices;
24 #if MOBILE
25 using XmlElement = System.Object;
26 #else
27 using System.Xml;
28 #endif
30 #if STATIC
31 using MetaType = IKVM.Reflection.Type;
32 using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
33 using IKVM.Reflection;
34 using IKVM.Reflection.Emit;
35 #else
36 using MetaType = System.Type;
37 using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
38 using System.Reflection;
39 using System.Reflection.Emit;
40 #endif
42 namespace Mono.CSharp {
44 public abstract class MethodCore : InterfaceMemberBase, IParametersMember
46 protected ParametersCompiled parameters;
47 protected ToplevelBlock block;
48 protected MethodSpec spec;
50 protected MethodCore (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod,
51 MemberName name, Attributes attrs, ParametersCompiled parameters)
52 : base (parent, type, mod, allowed_mod, name, attrs)
54 this.parameters = parameters;
57 public override Variance ExpectedMemberTypeVariance {
58 get {
59 return Variance.Covariant;
64 // Returns the System.Type array for the parameters of this method
66 public TypeSpec [] ParameterTypes {
67 get {
68 return parameters.Types;
72 public ParametersCompiled ParameterInfo {
73 get {
74 return parameters;
78 AParametersCollection IParametersMember.Parameters {
79 get { return parameters; }
82 public ToplevelBlock Block {
83 get {
84 return block;
87 set {
88 block = value;
92 public CallingConventions CallingConventions {
93 get {
94 CallingConventions cc = parameters.CallingConvention;
95 if (!IsInterface)
96 if ((ModFlags & Modifiers.STATIC) == 0)
97 cc |= CallingConventions.HasThis;
99 // FIXME: How is `ExplicitThis' used in C#?
101 return cc;
105 protected override bool CheckOverrideAgainstBase (MemberSpec base_member)
107 bool res = base.CheckOverrideAgainstBase (base_member);
110 // Check that the permissions are not being changed
112 if (!CheckAccessModifiers (this, base_member)) {
113 Error_CannotChangeAccessModifiers (this, base_member);
114 res = false;
117 return res;
120 protected override bool CheckBase ()
122 // Check whether arguments were correct.
123 if (!DefineParameters (parameters))
124 return false;
126 return base.CheckBase ();
130 // Represents header string for documentation comment.
132 public override string DocCommentHeader
134 get { return "M:"; }
137 public override void Emit ()
139 if ((ModFlags & Modifiers.COMPILER_GENERATED) == 0) {
140 parameters.CheckConstraints (this);
143 base.Emit ();
146 public override bool EnableOverloadChecks (MemberCore overload)
148 if (overload is MethodCore) {
149 caching_flags |= Flags.MethodOverloadsExist;
150 return true;
153 if (overload is AbstractPropertyEventMethod)
154 return true;
156 return base.EnableOverloadChecks (overload);
159 public override string GetSignatureForDocumentation ()
161 string s = base.GetSignatureForDocumentation ();
162 if (MemberName.Arity > 0)
163 s += "``" + MemberName.Arity.ToString ();
165 return s + parameters.GetSignatureForDocumentation ();
168 public override void PrepareEmit ()
170 base.PrepareEmit ();
171 parameters.ResolveDefaultValues (this);
174 public MethodSpec Spec {
175 get { return spec; }
178 protected override bool VerifyClsCompliance ()
180 if (!base.VerifyClsCompliance ())
181 return false;
183 if (parameters.HasArglist) {
184 Report.Warning (3000, 1, Location, "Methods with variable arguments are not CLS-compliant");
187 if (member_type != null && !member_type.IsCLSCompliant ()) {
188 Report.Warning (3002, 1, Location, "Return type of `{0}' is not CLS-compliant",
189 GetSignatureForError ());
192 parameters.VerifyClsCompliance (this);
193 return true;
197 public interface IGenericMethodDefinition : IMethodDefinition
199 TypeParameterSpec[] TypeParameters { get; }
200 int TypeParametersCount { get; }
202 // MethodInfo MakeGenericMethod (TypeSpec[] targs);
205 public sealed class MethodSpec : MemberSpec, IParametersMember
207 MethodBase inflatedMetaInfo;
208 AParametersCollection parameters;
209 TypeSpec returnType;
211 TypeSpec[] targs;
212 TypeParameterSpec[] constraints;
214 public static readonly MethodSpec Excluded = new MethodSpec (MemberKind.Method, InternalType.FakeInternalType, null, null, ParametersCompiled.EmptyReadOnlyParameters, 0);
216 public MethodSpec (MemberKind kind, TypeSpec declaringType, IMethodDefinition details, TypeSpec returnType,
217 AParametersCollection parameters, Modifiers modifiers)
218 : base (kind, declaringType, details, modifiers)
220 this.parameters = parameters;
221 this.returnType = returnType;
224 #region Properties
226 public override int Arity {
227 get {
228 return IsGeneric ? GenericDefinition.TypeParametersCount : 0;
232 public TypeParameterSpec[] Constraints {
233 get {
234 if (constraints == null && IsGeneric)
235 constraints = GenericDefinition.TypeParameters;
237 return constraints;
241 public bool IsConstructor {
242 get {
243 return Kind == MemberKind.Constructor;
247 public new IMethodDefinition MemberDefinition {
248 get {
249 return (IMethodDefinition) definition;
253 public IGenericMethodDefinition GenericDefinition {
254 get {
255 return (IGenericMethodDefinition) definition;
259 public bool IsAsync {
260 get {
261 return (Modifiers & Modifiers.ASYNC) != 0;
265 public bool IsExtensionMethod {
266 get {
267 return IsStatic && parameters.HasExtensionMethodType;
271 public bool IsSealed {
272 get {
273 return (Modifiers & Modifiers.SEALED) != 0;
277 // When is virtual or abstract
278 public bool IsVirtual {
279 get {
280 return (Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE)) != 0;
284 public bool IsReservedMethod {
285 get {
286 return Kind == MemberKind.Operator || IsAccessor;
290 TypeSpec IInterfaceMemberSpec.MemberType {
291 get {
292 return returnType;
296 public AParametersCollection Parameters {
297 get {
298 return parameters;
302 public TypeSpec ReturnType {
303 get {
304 return returnType;
308 public TypeSpec[] TypeArguments {
309 get {
310 return targs;
314 #endregion
316 public MethodSpec GetGenericMethodDefinition ()
318 if (!IsGeneric && !DeclaringType.IsGeneric)
319 return this;
321 return MemberCache.GetMember (declaringType, this);
324 public MethodBase GetMetaInfo ()
327 // inflatedMetaInfo is extra field needed for cases where we
328 // inflate method but another nested type can later inflate
329 // again (the cache would be build with inflated metaInfo) and
330 // TypeBuilder can work with method definitions only
332 if (inflatedMetaInfo == null) {
333 if ((state & StateFlags.PendingMetaInflate) != 0) {
334 var dt_meta = DeclaringType.GetMetaInfo ();
336 if (DeclaringType.IsTypeBuilder) {
337 if (IsConstructor)
338 inflatedMetaInfo = TypeBuilder.GetConstructor (dt_meta, (ConstructorInfo) MemberDefinition.Metadata);
339 else
340 inflatedMetaInfo = TypeBuilder.GetMethod (dt_meta, (MethodInfo) MemberDefinition.Metadata);
341 } else {
342 #if STATIC
343 // it should not be reached
344 throw new NotImplementedException ();
345 #else
346 inflatedMetaInfo = MethodInfo.GetMethodFromHandle (MemberDefinition.Metadata.MethodHandle, dt_meta.TypeHandle);
347 #endif
350 state &= ~StateFlags.PendingMetaInflate;
351 } else {
352 inflatedMetaInfo = MemberDefinition.Metadata;
356 if ((state & StateFlags.PendingMakeMethod) != 0) {
357 var sre_targs = new MetaType[targs.Length];
358 for (int i = 0; i < sre_targs.Length; ++i)
359 sre_targs[i] = targs[i].GetMetaInfo ();
361 inflatedMetaInfo = ((MethodInfo) inflatedMetaInfo).MakeGenericMethod (sre_targs);
362 state &= ~StateFlags.PendingMakeMethod;
365 return inflatedMetaInfo;
368 public override string GetSignatureForDocumentation ()
370 string name;
371 switch (Kind) {
372 case MemberKind.Constructor:
373 name = "#ctor";
374 break;
375 case MemberKind.Method:
376 if (Arity > 0)
377 name = Name + "``" + Arity.ToString ();
378 else
379 name = Name;
381 break;
382 default:
383 name = Name;
384 break;
387 name = DeclaringType.GetSignatureForDocumentation () + "." + name + parameters.GetSignatureForDocumentation ();
388 if (Kind == MemberKind.Operator) {
389 var op = Operator.GetType (Name).Value;
390 if (op == Operator.OpType.Explicit || op == Operator.OpType.Implicit) {
391 name += "~" + ReturnType.GetSignatureForDocumentation ();
395 return name;
398 public override string GetSignatureForError ()
400 string name;
401 if (IsConstructor) {
402 name = DeclaringType.GetSignatureForError () + "." + DeclaringType.Name;
403 } else if (Kind == MemberKind.Operator) {
404 var op = Operator.GetType (Name).Value;
405 if (op == Operator.OpType.Implicit || op == Operator.OpType.Explicit) {
406 name = DeclaringType.GetSignatureForError () + "." + Operator.GetName (op) + " operator " + returnType.GetSignatureForError ();
407 } else {
408 name = DeclaringType.GetSignatureForError () + ".operator " + Operator.GetName (op);
410 } else if (IsAccessor) {
411 int split = Name.IndexOf ('_');
412 name = Name.Substring (split + 1);
413 var postfix = Name.Substring (0, split);
414 if (split == 3) {
415 var pc = parameters.Count;
416 if (pc > 0 && postfix == "get") {
417 name = "this" + parameters.GetSignatureForError ("[", "]", pc);
418 } else if (pc > 1 && postfix == "set") {
419 name = "this" + parameters.GetSignatureForError ("[", "]", pc - 1);
423 return DeclaringType.GetSignatureForError () + "." + name + "." + postfix;
424 } else {
425 name = base.GetSignatureForError ();
426 if (targs != null)
427 name += "<" + TypeManager.CSharpName (targs) + ">";
428 else if (IsGeneric)
429 name += "<" + TypeManager.CSharpName (GenericDefinition.TypeParameters) + ">";
432 return name + parameters.GetSignatureForError ();
435 public override MemberSpec InflateMember (TypeParameterInflator inflator)
437 var ms = (MethodSpec) base.InflateMember (inflator);
438 ms.inflatedMetaInfo = null;
439 ms.returnType = inflator.Inflate (returnType);
440 ms.parameters = parameters.Inflate (inflator);
441 if (IsGeneric)
442 ms.constraints = TypeParameterSpec.InflateConstraints (inflator, Constraints);
444 return ms;
447 #if DEBUG
448 int counter = 100000;
449 #endif
451 public MethodSpec MakeGenericMethod (IMemberContext context, params TypeSpec[] targs)
453 if (targs == null)
454 throw new ArgumentNullException ();
455 // TODO MemberCache
456 // if (generic_intances != null && generic_intances.TryGetValue (targs, out ginstance))
457 // return ginstance;
459 //if (generic_intances == null)
460 // generic_intances = new Dictionary<TypeSpec[], Method> (TypeSpecArrayComparer.Default);
462 var inflator = new TypeParameterInflator (context, DeclaringType, GenericDefinition.TypeParameters, targs);
464 var inflated = (MethodSpec) MemberwiseClone ();
465 inflated.declaringType = inflator.TypeInstance;
466 inflated.returnType = inflator.Inflate (returnType);
467 inflated.parameters = parameters.Inflate (inflator);
468 inflated.targs = targs;
469 inflated.constraints = TypeParameterSpec.InflateConstraints (inflator, constraints ?? GenericDefinition.TypeParameters);
470 inflated.state |= StateFlags.PendingMakeMethod;
472 #if DEBUG
473 inflated.ID += counter;
474 counter += 100000;
475 #endif
476 // if (inflated.parent == null)
477 // inflated.parent = parent;
479 //generic_intances.Add (targs, inflated);
480 return inflated;
483 public MethodSpec Mutate (TypeParameterMutator mutator)
485 var targs = TypeArguments;
486 if (targs != null)
487 targs = mutator.Mutate (targs);
489 var decl = DeclaringType;
490 if (DeclaringType.IsGenericOrParentIsGeneric) {
491 decl = mutator.Mutate (decl);
494 if (targs == TypeArguments && decl == DeclaringType)
495 return this;
497 var ms = (MethodSpec) MemberwiseClone ();
498 if (decl != DeclaringType) {
499 ms.inflatedMetaInfo = null;
500 ms.declaringType = decl;
501 ms.state |= StateFlags.PendingMetaInflate;
504 if (targs != null) {
505 ms.targs = targs;
506 ms.state |= StateFlags.PendingMakeMethod;
509 return ms;
512 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
514 var missing = returnType.ResolveMissingDependencies (this);
515 foreach (var pt in parameters.Types) {
516 var m = pt.GetMissingDependencies (this);
517 if (m == null)
518 continue;
520 if (missing == null)
521 missing = new List<MissingTypeSpecReference> ();
523 missing.AddRange (m);
526 if (Arity > 0) {
527 foreach (var tp in GenericDefinition.TypeParameters) {
528 var m = tp.GetMissingDependencies (this);
530 if (m == null)
531 continue;
533 if (missing == null)
534 missing = new List<MissingTypeSpecReference> ();
536 missing.AddRange (m);
540 return missing;
544 public abstract class MethodOrOperator : MethodCore, IMethodData, IMethodDefinition
546 ReturnParameter return_attributes;
547 SecurityType declarative_security;
548 protected MethodData MethodData;
550 static readonly string[] attribute_targets = new string [] { "method", "return" };
552 protected MethodOrOperator (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name,
553 Attributes attrs, ParametersCompiled parameters)
554 : base (parent, type, mod, allowed_mod, name, attrs, parameters)
558 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
560 if (a.Target == AttributeTargets.ReturnValue) {
561 if (return_attributes == null)
562 return_attributes = new ReturnParameter (this, MethodBuilder, Location);
564 return_attributes.ApplyAttributeBuilder (a, ctor, cdata, pa);
565 return;
568 if (a.Type == pa.MethodImpl) {
569 if ((ModFlags & Modifiers.ASYNC) != 0 && (a.GetMethodImplOptions () & MethodImplOptions.Synchronized) != 0) {
570 Report.Error (4015, a.Location, "`{0}': Async methods cannot use `MethodImplOptions.Synchronized'",
571 GetSignatureForError ());
574 is_external_implementation = a.IsInternalCall ();
575 } else if (a.Type == pa.DllImport) {
576 const Modifiers extern_static = Modifiers.EXTERN | Modifiers.STATIC;
577 if ((ModFlags & extern_static) != extern_static) {
578 Report.Error (601, a.Location, "The DllImport attribute must be specified on a method marked `static' and `extern'");
581 if (MemberName.IsGeneric || Parent.IsGenericOrParentIsGeneric) {
582 Report.Error (7042, a.Location,
583 "The DllImport attribute cannot be applied to a method that is generic or contained in a generic type");
586 is_external_implementation = true;
589 if (a.IsValidSecurityAttribute ()) {
590 a.ExtractSecurityPermissionSet (ctor, ref declarative_security);
591 return;
594 if (MethodBuilder != null)
595 MethodBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
598 public override AttributeTargets AttributeTargets {
599 get {
600 return AttributeTargets.Method;
604 MethodBase IMethodDefinition.Metadata {
605 get {
606 return MethodData.MethodBuilder;
610 // TODO: Remove and use MethodData abstraction
611 public MethodBuilder MethodBuilder {
612 get {
613 return MethodData.MethodBuilder;
617 protected override bool CheckForDuplications ()
619 return Parent.MemberCache.CheckExistingMembersOverloads (this, parameters);
622 public virtual EmitContext CreateEmitContext (ILGenerator ig, SourceMethodBuilder sourceMethod)
624 return new EmitContext (this, ig, MemberType, sourceMethod);
627 public override bool Define ()
629 if (!base.Define ())
630 return false;
632 if (!CheckBase ())
633 return false;
635 MemberKind kind;
636 if (this is Operator)
637 kind = MemberKind.Operator;
638 else if (this is Destructor)
639 kind = MemberKind.Destructor;
640 else
641 kind = MemberKind.Method;
643 string explicit_name;
645 if (IsPartialDefinition) {
646 caching_flags &= ~Flags.Excluded_Undetected;
647 caching_flags |= Flags.Excluded;
649 // Add to member cache only when a partial method implementation has not been found yet
650 if ((caching_flags & Flags.PartialDefinitionExists) != 0)
651 return true;
653 if (IsExplicitImpl)
654 return true;
656 explicit_name = null;
657 } else {
658 MethodData = new MethodData (this, ModFlags, flags, this, base_method);
660 if (!MethodData.Define (Parent.PartialContainer, GetFullName (MemberName)))
661 return false;
663 explicit_name = MethodData.MetadataName;
666 spec = new MethodSpec (kind, Parent.Definition, this, ReturnType, parameters, ModFlags);
667 if (MemberName.Arity > 0)
668 spec.IsGeneric = true;
670 Parent.MemberCache.AddMember (this, explicit_name, spec);
672 return true;
675 protected override void DoMemberTypeIndependentChecks ()
677 base.DoMemberTypeIndependentChecks ();
679 CheckAbstractAndExtern (block != null);
681 if ((ModFlags & Modifiers.PARTIAL) != 0) {
682 for (int i = 0; i < parameters.Count; ++i) {
683 IParameterData p = parameters.FixedParameters [i];
684 if ((p.ModFlags & Parameter.Modifier.OUT) != 0) {
685 Report.Error (752, Location, "`{0}': A partial method parameters cannot use `out' modifier",
686 GetSignatureForError ());
689 if (p.HasDefaultValue && IsPartialImplementation)
690 ((Parameter) p).Warning_UselessOptionalParameter (Report);
695 protected override void DoMemberTypeDependentChecks ()
697 base.DoMemberTypeDependentChecks ();
699 if (MemberType.IsStatic) {
700 Error_StaticReturnType ();
704 public override void Emit ()
706 if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
707 Module.PredefinedAttributes.CompilerGenerated.EmitAttribute (MethodBuilder);
708 if ((ModFlags & Modifiers.DEBUGGER_HIDDEN) != 0)
709 Module.PredefinedAttributes.DebuggerHidden.EmitAttribute (MethodBuilder);
710 if ((ModFlags & Modifiers.DEBUGGER_STEP_THROUGH) != 0)
711 Module.PredefinedAttributes.DebuggerStepThrough.EmitAttribute (MethodBuilder);
713 if (ReturnType.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
714 return_attributes = new ReturnParameter (this, MethodBuilder, Location);
715 Module.PredefinedAttributes.Dynamic.EmitAttribute (return_attributes.Builder);
716 } else if (ReturnType.HasDynamicElement) {
717 return_attributes = new ReturnParameter (this, MethodBuilder, Location);
718 Module.PredefinedAttributes.Dynamic.EmitAttribute (return_attributes.Builder, ReturnType, Location);
721 if (OptAttributes != null)
722 OptAttributes.Emit ();
724 if (declarative_security != null) {
725 foreach (var de in declarative_security) {
726 #if STATIC
727 MethodBuilder.__AddDeclarativeSecurity (de);
728 #else
729 MethodBuilder.AddDeclarativeSecurity (de.Key, de.Value);
730 #endif
735 // Optimization but it also covers cases where we cannot check
736 // constraints because method is captured into generated class
737 // and type parameters context is now different
739 if (type_expr != null && !IsCompilerGenerated)
740 ConstraintChecker.Check (this, member_type, type_expr.Location);
742 base.Emit ();
744 if (MethodData != null)
745 MethodData.Emit (Parent);
747 if (block != null && block.StateMachine is AsyncTaskStorey) {
748 var psm = Module.PredefinedAttributes.AsyncStateMachine;
749 psm.EmitAttribute (MethodBuilder, block.StateMachine);
752 if ((ModFlags & Modifiers.PARTIAL) == 0)
753 Block = null;
756 protected void Error_ConditionalAttributeIsNotValid ()
758 Report.Error (577, Location,
759 "Conditional not valid on `{0}' because it is a constructor, destructor, operator or explicit interface implementation",
760 GetSignatureForError ());
763 public bool IsPartialDefinition {
764 get {
765 return (ModFlags & Modifiers.PARTIAL) != 0 && Block == null;
769 public bool IsPartialImplementation {
770 get {
771 return (ModFlags & Modifiers.PARTIAL) != 0 && Block != null;
775 public override string[] ValidAttributeTargets {
776 get {
777 return attribute_targets;
781 #region IMethodData Members
783 bool IMethodData.IsAccessor {
784 get {
785 return false;
789 public TypeSpec ReturnType {
790 get {
791 return MemberType;
795 public MemberName MethodName {
796 get {
797 return MemberName;
801 /// <summary>
802 /// Returns true if method has conditional attribute and the conditions is not defined (method is excluded).
803 /// </summary>
804 public override string[] ConditionalConditions ()
806 if ((caching_flags & (Flags.Excluded_Undetected | Flags.Excluded)) == 0)
807 return null;
809 if ((ModFlags & Modifiers.PARTIAL) != 0 && (caching_flags & Flags.Excluded) != 0)
810 return new string [0];
812 caching_flags &= ~Flags.Excluded_Undetected;
813 string[] conditions;
815 if (base_method == null) {
816 if (OptAttributes == null)
817 return null;
819 Attribute[] attrs = OptAttributes.SearchMulti (Module.PredefinedAttributes.Conditional);
820 if (attrs == null)
821 return null;
823 conditions = new string[attrs.Length];
824 for (int i = 0; i < conditions.Length; ++i)
825 conditions[i] = attrs[i].GetConditionalAttributeValue ();
826 } else {
827 conditions = base_method.MemberDefinition.ConditionalConditions();
830 if (conditions != null)
831 caching_flags |= Flags.Excluded;
833 return conditions;
836 #endregion
838 public override void PrepareEmit ()
840 base.PrepareEmit ();
842 var mb = MethodData.DefineMethodBuilder (Parent);
844 if (CurrentTypeParameters != null) {
845 string[] gnames = new string[CurrentTypeParameters.Count];
846 for (int i = 0; i < gnames.Length; ++i) {
847 gnames[i] = CurrentTypeParameters[i].Name;
850 var gen_params = MethodBuilder.DefineGenericParameters (gnames);
852 for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
853 var tp = CurrentTypeParameters[i];
855 tp.Define (gen_params[i]);
860 // Generic method has been already defined to resolve method parameters
861 // correctly when they use type parameters
863 mb.SetParameters (parameters.GetMetaInfo ());
864 mb.SetReturnType (ReturnType.GetMetaInfo ());
867 public override void WriteDebugSymbol (MonoSymbolFile file)
869 if (MethodData != null && !IsPartialDefinition)
870 MethodData.WriteDebugSymbol (file);
874 public class Method : MethodOrOperator, IGenericMethodDefinition
876 Method partialMethodImplementation;
878 public Method (TypeDefinition parent, FullNamedExpression return_type, Modifiers mod, MemberName name, ParametersCompiled parameters, Attributes attrs)
879 : base (parent, return_type, mod,
880 parent.PartialContainer.Kind == MemberKind.Interface ? AllowedModifiersInterface :
881 parent.PartialContainer.Kind == MemberKind.Struct ? AllowedModifiersStruct | Modifiers.ASYNC :
882 AllowedModifiersClass | Modifiers.ASYNC,
883 name, attrs, parameters)
887 protected Method (TypeDefinition parent, FullNamedExpression return_type, Modifiers mod, Modifiers amod,
888 MemberName name, ParametersCompiled parameters, Attributes attrs)
889 : base (parent, return_type, mod, amod, name, attrs, parameters)
893 #region Properties
895 public override TypeParameters CurrentTypeParameters {
896 get {
897 return MemberName.TypeParameters;
901 public TypeParameterSpec[] TypeParameters {
902 get {
903 return CurrentTypeParameters.Types;
907 public int TypeParametersCount {
908 get {
909 return CurrentTypeParameters == null ? 0 : CurrentTypeParameters.Count;
913 #endregion
915 public override void Accept (StructuralVisitor visitor)
917 visitor.Visit (this);
920 public static Method Create (TypeDefinition parent, FullNamedExpression returnType, Modifiers mod,
921 MemberName name, ParametersCompiled parameters, Attributes attrs)
923 var m = new Method (parent, returnType, mod, name, parameters, attrs);
925 if ((mod & Modifiers.PARTIAL) != 0) {
926 const Modifiers invalid_partial_mod = Modifiers.AccessibilityMask | Modifiers.ABSTRACT | Modifiers.EXTERN |
927 Modifiers.NEW | Modifiers.OVERRIDE | Modifiers.SEALED | Modifiers.VIRTUAL;
929 if ((mod & invalid_partial_mod) != 0) {
930 m.Report.Error (750, m.Location,
931 "A partial method cannot define access modifier or any of abstract, extern, new, override, sealed, or virtual modifiers");
932 mod &= ~invalid_partial_mod;
935 if ((parent.ModFlags & Modifiers.PARTIAL) == 0) {
936 m.Report.Error (751, m.Location,
937 "A partial method must be declared within a partial class or partial struct");
941 if ((mod & Modifiers.STATIC) == 0 && parameters.HasExtensionMethodType) {
942 m.Report.Error (1105, m.Location, "`{0}': Extension methods must be declared static",
943 m.GetSignatureForError ());
947 return m;
950 public override string GetSignatureForError()
952 return base.GetSignatureForError () + parameters.GetSignatureForError ();
955 void Error_DuplicateEntryPoint (Method b)
957 Report.Error (17, b.Location,
958 "Program `{0}' has more than one entry point defined: `{1}'",
959 b.Module.Builder.ScopeName, b.GetSignatureForError ());
962 bool IsEntryPoint ()
964 if (ReturnType.Kind != MemberKind.Void && ReturnType.BuiltinType != BuiltinTypeSpec.Type.Int)
965 return false;
967 if (parameters.IsEmpty)
968 return true;
970 if (parameters.Count > 1)
971 return false;
973 var ac = parameters.Types [0] as ArrayContainer;
974 return ac != null && ac.Rank == 1 && ac.Element.BuiltinType == BuiltinTypeSpec.Type.String &&
975 (parameters[0].ModFlags & Parameter.Modifier.RefOutMask) == 0;
978 public override FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
980 if (arity == 0) {
981 var tp = CurrentTypeParameters;
982 if (tp != null) {
983 TypeParameter t = tp.Find (name);
984 if (t != null)
985 return new TypeParameterExpr (t, loc);
989 return base.LookupNamespaceOrType (name, arity, mode, loc);
992 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
994 if (a.Type == pa.Conditional) {
995 if (IsExplicitImpl) {
996 Error_ConditionalAttributeIsNotValid ();
997 return;
1000 if ((ModFlags & Modifiers.OVERRIDE) != 0) {
1001 Report.Error (243, Location, "Conditional not valid on `{0}' because it is an override method", GetSignatureForError ());
1002 return;
1005 if (ReturnType.Kind != MemberKind.Void) {
1006 Report.Error (578, Location, "Conditional not valid on `{0}' because its return type is not void", GetSignatureForError ());
1007 return;
1010 if (IsInterface) {
1011 Report.Error (582, Location, "Conditional not valid on interface members");
1012 return;
1015 if (MethodData.implementing != null) {
1016 Report.SymbolRelatedToPreviousError (MethodData.implementing.DeclaringType);
1017 Report.Error (629, Location, "Conditional member `{0}' cannot implement interface member `{1}'",
1018 GetSignatureForError (), TypeManager.CSharpSignature (MethodData.implementing));
1019 return;
1022 for (int i = 0; i < parameters.Count; ++i) {
1023 if ((parameters.FixedParameters [i].ModFlags & Parameter.Modifier.OUT) != 0) {
1024 Report.Error (685, Location, "Conditional method `{0}' cannot have an out parameter", GetSignatureForError ());
1025 return;
1030 if (a.Type == pa.Extension) {
1031 a.Error_MisusedExtensionAttribute ();
1032 return;
1035 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
1038 void CreateTypeParameters ()
1040 var tparams = MemberName.TypeParameters;
1041 var parent_tparams = Parent.TypeParametersAll;
1043 for (int i = 0; i < MemberName.Arity; i++) {
1044 string type_argument_name = tparams[i].MemberName.Name;
1046 if (block == null) {
1047 int idx = parameters.GetParameterIndexByName (type_argument_name);
1048 if (idx >= 0) {
1049 var b = block;
1050 if (b == null)
1051 b = new ToplevelBlock (Compiler, Location);
1053 b.Error_AlreadyDeclaredTypeParameter (type_argument_name, parameters[i].Location);
1055 } else {
1056 INamedBlockVariable variable = null;
1057 block.GetLocalName (type_argument_name, block, ref variable);
1058 if (variable != null)
1059 variable.Block.Error_AlreadyDeclaredTypeParameter (type_argument_name, variable.Location);
1062 if (parent_tparams != null) {
1063 var tp = parent_tparams.Find (type_argument_name);
1064 if (tp != null) {
1065 tparams[i].WarningParentNameConflict (tp);
1070 tparams.Create (null, 0, Parent);
1073 protected virtual void DefineTypeParameters ()
1075 var tparams = CurrentTypeParameters;
1077 TypeParameterSpec[] base_tparams = null;
1078 TypeParameterSpec[] base_decl_tparams = TypeParameterSpec.EmptyTypes;
1079 TypeSpec[] base_targs = TypeSpec.EmptyTypes;
1080 if (((ModFlags & Modifiers.OVERRIDE) != 0 || IsExplicitImpl)) {
1081 MethodSpec base_override = base_method ?? MethodData.implementing;
1083 if (base_override != null) {
1084 base_tparams = base_override.GenericDefinition.TypeParameters;
1086 if (base_override.DeclaringType.IsGeneric) {
1087 base_decl_tparams = base_override.DeclaringType.MemberDefinition.TypeParameters;
1089 if (base_method != null) {
1090 var base_type_parent = CurrentType;
1091 while (base_type_parent.BaseType != base_override.DeclaringType) {
1092 base_type_parent = base_type_parent.BaseType;
1095 base_targs = base_type_parent.BaseType.TypeArguments;
1096 } else {
1097 foreach (var iface in Parent.CurrentType.Interfaces) {
1098 if (iface == base_override.DeclaringType) {
1099 base_targs = iface.TypeArguments;
1100 break;
1106 if (base_override.IsGeneric) {
1107 foreach (var base_tp in base_tparams) {
1108 base_tp.BaseType.CheckObsoleteness (this, Location);
1110 if (base_tp.InterfacesDefined != null) {
1111 foreach (var iface in base_tp.InterfacesDefined) {
1112 iface.CheckObsoleteness (this, Location);
1117 if (base_decl_tparams.Length != 0) {
1118 base_decl_tparams = base_decl_tparams.Concat (base_tparams).ToArray ();
1119 base_targs = base_targs.Concat (tparams.Types).ToArray ();
1120 } else {
1121 base_decl_tparams = base_tparams;
1122 base_targs = tparams.Types;
1128 for (int i = 0; i < tparams.Count; ++i) {
1129 var tp = tparams [i];
1131 if (base_tparams == null) {
1132 tp.ResolveConstraints (this);
1133 continue;
1137 // Copy base constraints for override/explicit methods
1139 var base_tparam = base_tparams [i];
1140 var local_tparam = tp.Type;
1141 local_tparam.SpecialConstraint = base_tparam.SpecialConstraint;
1143 var inflator = new TypeParameterInflator (this, CurrentType, base_decl_tparams, base_targs);
1144 base_tparam.InflateConstraints (inflator, local_tparam);
1147 // Check all type argument constraints for possible collision or unification
1148 // introduced by inflating inherited constraints in this context
1150 // Conflict example:
1152 // class A<T> { virtual void Foo<U> () where U : class, T {} }
1153 // class B : A<int> { override void Foo<U> {} }
1155 var local_tparam_targs = local_tparam.TypeArguments;
1156 if (local_tparam_targs != null) {
1157 for (int ii = 0; ii < local_tparam_targs.Length; ++ii) {
1158 var ta = local_tparam_targs [ii];
1159 if (!ta.IsClass && !ta.IsStruct)
1160 continue;
1162 TypeSpec[] unique_tparams = null;
1163 for (int iii = ii + 1; iii < local_tparam_targs.Length; ++iii) {
1165 // Remove any identical or unified constraint types
1167 var tparam_checked = local_tparam_targs [iii];
1168 if (TypeSpecComparer.IsEqual (ta, tparam_checked) || TypeSpec.IsBaseClass (ta, tparam_checked, false)) {
1169 unique_tparams = new TypeSpec[local_tparam_targs.Length - 1];
1170 Array.Copy (local_tparam_targs, 0, unique_tparams, 0, iii);
1171 Array.Copy (local_tparam_targs, iii + 1, unique_tparams, iii, local_tparam_targs.Length - iii - 1);
1172 } else if (!TypeSpec.IsBaseClass (tparam_checked, ta, false)) {
1173 Constraints.Error_ConflictingConstraints (this, local_tparam, ta, tparam_checked, Location);
1177 if (unique_tparams != null) {
1178 local_tparam_targs = unique_tparams;
1179 local_tparam.TypeArguments = local_tparam_targs;
1180 continue;
1183 Constraints.CheckConflictingInheritedConstraint (local_tparam, ta, this, Location);
1188 if (base_tparams == null && MethodData != null && MethodData.implementing != null) {
1189 CheckImplementingMethodConstraints (Parent, spec, MethodData.implementing);
1193 public static bool CheckImplementingMethodConstraints (TypeContainer container, MethodSpec method, MethodSpec baseMethod)
1195 var tparams = method.Constraints;
1196 var base_tparams = baseMethod.Constraints;
1197 for (int i = 0; i < tparams.Length; ++i) {
1198 if (!tparams[i].HasSameConstraintsImplementation (base_tparams[i])) {
1199 container.Compiler.Report.SymbolRelatedToPreviousError (method);
1200 container.Compiler.Report.SymbolRelatedToPreviousError (baseMethod);
1202 // Using container location because the interface can be implemented
1203 // by base class
1204 var tp = (tparams [i].MemberDefinition as MemberCore) ?? container;
1205 container.Compiler.Report.Error (425, tp.Location,
1206 "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",
1207 tparams[i].GetSignatureForError (), method.GetSignatureForError (),
1208 base_tparams[i].GetSignatureForError (), baseMethod.GetSignatureForError ());
1210 return false;
1214 return true;
1218 // Creates the type
1220 public override bool Define ()
1222 if (!base.Define ())
1223 return false;
1225 if (member_type.Kind == MemberKind.Void && parameters.IsEmpty && MemberName.Arity == 0 && MemberName.Name == Destructor.MetadataName) {
1226 Report.Warning (465, 1, Location,
1227 "Introducing `Finalize' method can interfere with destructor invocation. Did you intend to declare a destructor?");
1230 if (Compiler.Settings.StdLib && ReturnType.IsSpecialRuntimeType) {
1231 Error1599 (Location, ReturnType, Report);
1232 return false;
1235 if (CurrentTypeParameters == null) {
1236 if (base_method != null && !IsExplicitImpl) {
1237 if (parameters.Count == 1 && ParameterTypes[0].BuiltinType == BuiltinTypeSpec.Type.Object && MemberName.Name == "Equals")
1238 Parent.PartialContainer.Mark_HasEquals ();
1239 else if (parameters.IsEmpty && MemberName.Name == "GetHashCode")
1240 Parent.PartialContainer.Mark_HasGetHashCode ();
1243 } else {
1244 DefineTypeParameters ();
1247 if (block != null) {
1248 if (block.IsIterator) {
1250 // Current method is turned into automatically generated
1251 // wrapper which creates an instance of iterator
1253 Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags);
1254 ModFlags |= Modifiers.DEBUGGER_HIDDEN;
1257 if ((ModFlags & Modifiers.ASYNC) != 0) {
1258 if (ReturnType.Kind != MemberKind.Void &&
1259 ReturnType != Module.PredefinedTypes.Task.TypeSpec &&
1260 !ReturnType.IsGenericTask) {
1261 Report.Error (1983, Location, "The return type of an async method must be void, Task, or Task<T>");
1264 block = (ToplevelBlock) block.ConvertToAsyncTask (this, Parent.PartialContainer, parameters, ReturnType, null, Location);
1265 ModFlags |= Modifiers.DEBUGGER_STEP_THROUGH;
1268 if (Compiler.Settings.WriteMetadataOnly)
1269 block = null;
1272 if ((ModFlags & Modifiers.STATIC) == 0)
1273 return true;
1275 if (parameters.HasExtensionMethodType) {
1276 if (Parent.PartialContainer.IsStatic && !Parent.IsGenericOrParentIsGeneric) {
1277 if (!Parent.IsTopLevel)
1278 Report.Error (1109, Location, "`{0}': Extension methods cannot be defined in a nested class",
1279 GetSignatureForError ());
1281 PredefinedAttribute pa = Module.PredefinedAttributes.Extension;
1282 if (!pa.IsDefined) {
1283 Report.Error (1110, Location,
1284 "`{0}': Extension methods require `System.Runtime.CompilerServices.ExtensionAttribute' type to be available. Are you missing an assembly reference?",
1285 GetSignatureForError ());
1288 ModFlags |= Modifiers.METHOD_EXTENSION;
1289 Parent.PartialContainer.ModFlags |= Modifiers.METHOD_EXTENSION;
1290 Spec.DeclaringType.SetExtensionMethodContainer ();
1291 Parent.Module.HasExtensionMethod = true;
1292 } else {
1293 Report.Error (1106, Location, "`{0}': Extension methods must be defined in a non-generic static class",
1294 GetSignatureForError ());
1299 // This is used to track the Entry Point,
1301 var settings = Compiler.Settings;
1302 if (settings.NeedsEntryPoint && MemberName.Name == "Main" && !IsPartialDefinition && (settings.MainClass == null || settings.MainClass == Parent.TypeBuilder.FullName)) {
1303 if (IsEntryPoint ()) {
1304 if (Parent.DeclaringAssembly.EntryPoint == null) {
1305 if (Parent.IsGenericOrParentIsGeneric || MemberName.IsGeneric) {
1306 Report.Warning (402, 4, Location, "`{0}': an entry point cannot be generic or in a generic type",
1307 GetSignatureForError ());
1308 } else if ((ModFlags & Modifiers.ASYNC) != 0) {
1309 Report.Error (4009, Location, "`{0}': an entry point cannot be async method",
1310 GetSignatureForError ());
1311 } else {
1312 SetIsUsed ();
1313 Parent.DeclaringAssembly.EntryPoint = this;
1315 } else {
1316 Error_DuplicateEntryPoint (Parent.DeclaringAssembly.EntryPoint);
1317 Error_DuplicateEntryPoint (this);
1319 } else {
1320 Report.Warning (28, 4, Location, "`{0}' has the wrong signature to be an entry point",
1321 GetSignatureForError ());
1325 return true;
1328 public override void PrepareEmit ()
1330 if (IsPartialDefinition) {
1332 // Use partial method implementation builder for partial method declaration attributes
1334 if (partialMethodImplementation != null) {
1335 MethodData = partialMethodImplementation.MethodData;
1338 return;
1341 base.PrepareEmit ();
1345 // Emits the code
1347 public override void Emit ()
1349 try {
1350 if (IsPartialDefinition) {
1351 if (partialMethodImplementation != null && CurrentTypeParameters != null) {
1352 CurrentTypeParameters.CheckPartialConstraints (partialMethodImplementation);
1354 var otp = partialMethodImplementation.CurrentTypeParameters;
1355 for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
1356 var tp = CurrentTypeParameters [i];
1357 tp.Define (otp[i]);
1361 return;
1364 if ((ModFlags & Modifiers.PARTIAL) != 0 && (caching_flags & Flags.PartialDefinitionExists) == 0) {
1365 Report.Error (759, Location, "A partial method `{0}' implementation is missing a partial method declaration",
1366 GetSignatureForError ());
1369 if (CurrentTypeParameters != null) {
1370 for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
1371 var tp = CurrentTypeParameters [i];
1373 tp.CheckGenericConstraints (false);
1374 tp.Emit ();
1378 if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
1379 Module.PredefinedAttributes.Extension.EmitAttribute (MethodBuilder);
1381 base.Emit ();
1382 } catch (Exception e) {
1383 throw new InternalErrorException (this, e);
1387 public override bool EnableOverloadChecks (MemberCore overload)
1389 if (overload is Indexer)
1390 return false;
1392 return base.EnableOverloadChecks (overload);
1395 public static void Error1599 (Location loc, TypeSpec t, Report Report)
1397 Report.Error (1599, loc, "Method or delegate cannot return type `{0}'", t.GetSignatureForError ());
1400 protected override bool ResolveMemberType ()
1402 if (CurrentTypeParameters != null) {
1403 CreateTypeParameters ();
1406 return base.ResolveMemberType ();
1409 public void SetPartialDefinition (Method methodDefinition)
1411 caching_flags |= Flags.PartialDefinitionExists;
1412 methodDefinition.partialMethodImplementation = this;
1414 // Ensure we are always using method declaration parameters
1415 for (int i = 0; i < methodDefinition.parameters.Count; ++i ) {
1416 var md_p = methodDefinition.parameters [i];
1417 var p = parameters [i];
1418 p.Name = md_p.Name;
1419 p.DefaultValue = md_p.DefaultValue;
1420 if (md_p.OptAttributes != null) {
1421 Attributes.AttachFromPartial (p, md_p);
1425 if (methodDefinition.attributes != null) {
1426 if (attributes == null) {
1427 attributes = methodDefinition.attributes;
1428 } else {
1429 attributes.Attrs.AddRange (methodDefinition.attributes.Attrs);
1433 if (CurrentTypeParameters != null) {
1434 for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
1435 var tp_other = methodDefinition.CurrentTypeParameters [i];
1436 if (tp_other.OptAttributes == null)
1437 continue;
1439 var tp = CurrentTypeParameters [i];
1440 if (tp.OptAttributes == null) {
1441 tp.OptAttributes = tp_other.OptAttributes;
1442 } else {
1443 tp.OptAttributes.Attrs.AddRange (tp.OptAttributes.Attrs);
1450 public abstract class ConstructorInitializer : ExpressionStatement
1452 Arguments argument_list;
1453 MethodSpec base_ctor;
1455 protected ConstructorInitializer (Arguments argument_list, Location loc)
1457 this.argument_list = argument_list;
1458 this.loc = loc;
1461 public Arguments Arguments {
1462 get {
1463 return argument_list;
1467 public override bool ContainsEmitWithAwait ()
1469 throw new NotSupportedException ();
1472 public override Expression CreateExpressionTree (ResolveContext ec)
1474 throw new NotSupportedException ("ET");
1477 protected override Expression DoResolve (ResolveContext ec)
1479 eclass = ExprClass.Value;
1481 // FIXME: Hack
1482 var caller_builder = (Constructor) ec.MemberContext;
1485 // Spec mandates that constructor initializer will not have `this' access
1487 using (ec.Set (ResolveContext.Options.BaseInitializer)) {
1488 if (argument_list != null) {
1489 bool dynamic;
1490 argument_list.Resolve (ec, out dynamic);
1492 if (dynamic) {
1493 ec.Report.Error (1975, loc,
1494 "The constructor call cannot be dynamically dispatched within constructor initializer");
1496 return null;
1500 type = ec.CurrentType;
1501 if (this is ConstructorBaseInitializer) {
1502 if (ec.CurrentType.BaseType == null)
1503 return this;
1505 type = ec.CurrentType.BaseType;
1506 if (ec.CurrentType.IsStruct) {
1507 ec.Report.Error (522, loc,
1508 "`{0}': Struct constructors cannot call base constructors", caller_builder.GetSignatureForError ());
1509 return this;
1513 base_ctor = ConstructorLookup (ec, type, ref argument_list, loc);
1516 if (base_ctor != null && base_ctor.MemberDefinition == caller_builder.Spec.MemberDefinition) {
1517 ec.Report.Error (516, loc, "Constructor `{0}' cannot call itself",
1518 caller_builder.GetSignatureForError ());
1521 return this;
1524 public override void Emit (EmitContext ec)
1527 // It can be null for struct initializers or System.Object
1529 if (base_ctor == null) {
1530 if (type == ec.BuiltinTypes.Object)
1531 return;
1533 ec.Emit (OpCodes.Ldarg_0);
1534 ec.Emit (OpCodes.Initobj, type);
1535 return;
1538 var call = new CallEmitter ();
1539 call.InstanceExpression = new CompilerGeneratedThis (type, loc);
1540 call.EmitPredefined (ec, base_ctor, argument_list, false);
1543 public override void EmitStatement (EmitContext ec)
1545 Emit (ec);
1548 public override void FlowAnalysis (FlowAnalysisContext fc)
1550 if (argument_list != null)
1551 argument_list.FlowAnalysis (fc);
1555 public class ConstructorBaseInitializer : ConstructorInitializer {
1556 public ConstructorBaseInitializer (Arguments argument_list, Location l) :
1557 base (argument_list, l)
1562 class GeneratedBaseInitializer: ConstructorBaseInitializer {
1563 public GeneratedBaseInitializer (Location loc, Arguments arguments)
1564 : base (arguments, loc)
1569 public class ConstructorThisInitializer : ConstructorInitializer {
1570 public ConstructorThisInitializer (Arguments argument_list, Location l) :
1571 base (argument_list, l)
1576 public class Constructor : MethodCore, IMethodData, IMethodDefinition
1578 public ConstructorBuilder ConstructorBuilder;
1579 public ConstructorInitializer Initializer;
1580 SecurityType declarative_security;
1581 bool has_compliant_args;
1582 SourceMethodBuilder debug_builder;
1584 // <summary>
1585 // Modifiers allowed for a constructor.
1586 // </summary>
1587 public const Modifiers AllowedModifiers =
1588 Modifiers.PUBLIC |
1589 Modifiers.PROTECTED |
1590 Modifiers.INTERNAL |
1591 Modifiers.STATIC |
1592 Modifiers.UNSAFE |
1593 Modifiers.EXTERN |
1594 Modifiers.PRIVATE;
1596 static readonly string[] attribute_targets = new string [] { "method" };
1598 public static readonly string ConstructorName = ".ctor";
1599 public static readonly string TypeConstructorName = ".cctor";
1601 public Constructor (TypeDefinition parent, string name, Modifiers mod, Attributes attrs, ParametersCompiled args, Location loc)
1602 : base (parent, null, mod, AllowedModifiers, new MemberName (name, loc), attrs, args)
1606 public bool HasCompliantArgs {
1607 get {
1608 return has_compliant_args;
1612 public override AttributeTargets AttributeTargets {
1613 get {
1614 return AttributeTargets.Constructor;
1618 bool IMethodData.IsAccessor {
1619 get {
1620 return false;
1624 public bool IsPrimaryConstructor { get; set; }
1626 MethodBase IMethodDefinition.Metadata {
1627 get {
1628 return ConstructorBuilder;
1633 // Returns true if this is a default constructor
1635 public bool IsDefault ()
1637 if ((ModFlags & Modifiers.STATIC) != 0)
1638 return parameters.IsEmpty;
1640 return parameters.IsEmpty &&
1641 (Initializer is ConstructorBaseInitializer) &&
1642 (Initializer.Arguments == null);
1645 public override void Accept (StructuralVisitor visitor)
1647 visitor.Visit (this);
1650 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1652 if (a.IsValidSecurityAttribute ()) {
1653 a.ExtractSecurityPermissionSet (ctor, ref declarative_security);
1654 return;
1657 if (a.Type == pa.MethodImpl) {
1658 is_external_implementation = a.IsInternalCall ();
1661 ConstructorBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
1664 protected override bool CheckBase ()
1666 if ((ModFlags & Modifiers.STATIC) != 0) {
1667 if ((caching_flags & Flags.MethodOverloadsExist) != 0)
1668 Parent.MemberCache.CheckExistingMembersOverloads (this, parameters);
1670 // the rest can be ignored
1671 return true;
1674 // Check whether arguments were correct.
1675 if (!DefineParameters (parameters))
1676 return false;
1678 if ((caching_flags & Flags.MethodOverloadsExist) != 0)
1679 Parent.MemberCache.CheckExistingMembersOverloads (this, parameters);
1681 CheckProtectedModifier ();
1683 return true;
1687 // Creates the ConstructorBuilder
1689 public override bool Define ()
1691 if (ConstructorBuilder != null)
1692 return true;
1694 if (!CheckAbstractAndExtern (block != null))
1695 return false;
1697 // Check if arguments were correct.
1698 if (!CheckBase ())
1699 return false;
1701 if (Parent.PrimaryConstructorParameters != null && !IsPrimaryConstructor && !IsStatic) {
1702 if (Parent.Kind == MemberKind.Struct && Initializer is ConstructorThisInitializer && Initializer.Arguments == null) {
1703 Report.Error (8043, Location, "`{0}': Structs with primary constructor cannot specify default constructor initializer",
1704 GetSignatureForError ());
1705 } else if (Initializer == null || Initializer is ConstructorBaseInitializer) {
1706 Report.Error (8037, Location, "`{0}': Instance constructor of type with primary constructor must specify `this' constructor initializer",
1707 GetSignatureForError ());
1711 if ((ModFlags & Modifiers.EXTERN) != 0 && Initializer != null) {
1712 Report.Error (8091, Location, "`{0}': Contructors cannot be extern and have a constructor initializer",
1713 GetSignatureForError ());
1716 var ca = ModifiersExtensions.MethodAttr (ModFlags) | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName;
1718 ConstructorBuilder = Parent.TypeBuilder.DefineConstructor (
1719 ca, CallingConventions,
1720 parameters.GetMetaInfo ());
1722 spec = new MethodSpec (MemberKind.Constructor, Parent.Definition, this, Compiler.BuiltinTypes.Void, parameters, ModFlags);
1724 Parent.MemberCache.AddMember (spec);
1726 if (block != null) {
1727 // It's here only to report an error
1728 if (block.IsIterator) {
1729 member_type = Compiler.BuiltinTypes.Void;
1730 Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags);
1733 if (Compiler.Settings.WriteMetadataOnly)
1734 block = null;
1737 return true;
1741 // Emits the code
1743 public override void Emit ()
1745 if (Parent.PartialContainer.IsComImport) {
1746 if (!IsDefault ()) {
1747 Report.Error (669, Location, "`{0}': A class with the ComImport attribute cannot have a user-defined constructor",
1748 Parent.GetSignatureForError ());
1751 // Set as internal implementation and reset block data
1752 // to ensure no IL is generated
1753 ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.InternalCall);
1754 block = null;
1757 if ((ModFlags & Modifiers.DEBUGGER_HIDDEN) != 0)
1758 Module.PredefinedAttributes.DebuggerHidden.EmitAttribute (ConstructorBuilder);
1760 if (OptAttributes != null)
1761 OptAttributes.Emit ();
1763 base.Emit ();
1764 parameters.ApplyAttributes (this, ConstructorBuilder);
1767 BlockContext bc = new BlockContext (this, block, Compiler.BuiltinTypes.Void);
1768 bc.Set (ResolveContext.Options.ConstructorScope);
1770 if (block != null) {
1771 if (!IsStatic && Initializer == null && Parent.PartialContainer.Kind == MemberKind.Struct) {
1773 // If this is a non-static `struct' constructor and doesn't have any
1774 // initializer, it must initialize all of the struct's fields.
1776 block.AddThisVariable (bc);
1780 // If we use a "this (...)" constructor initializer, then
1781 // do not emit field initializers, they are initialized in the other constructor
1783 if (!(Initializer is ConstructorThisInitializer)) {
1784 var errors = Compiler.Report.Errors;
1785 Parent.PartialContainer.ResolveFieldInitializers (bc);
1786 if (errors != Compiler.Report.Errors)
1787 return;
1790 if (!IsStatic) {
1791 if (Initializer == null && Parent.PartialContainer.Kind == MemberKind.Class) {
1792 Initializer = new GeneratedBaseInitializer (Location, null);
1795 if (Initializer != null) {
1797 // mdb format does not support reqions. Try to workaround this by emitting the
1798 // sequence point at initializer. Any breakpoint at constructor header should
1799 // be adjusted to this sequence point as it's the next one which follows.
1801 block.AddScopeStatement (new StatementExpression (Initializer));
1805 if (block.Resolve (bc, this)) {
1806 debug_builder = Parent.CreateMethodSymbolEntry ();
1807 EmitContext ec = new EmitContext (this, ConstructorBuilder.GetILGenerator (), bc.ReturnType, debug_builder);
1808 ec.With (EmitContext.Options.ConstructorScope, true);
1810 block.Emit (ec);
1814 if (declarative_security != null) {
1815 foreach (var de in declarative_security) {
1816 #if STATIC
1817 ConstructorBuilder.__AddDeclarativeSecurity (de);
1818 #else
1819 ConstructorBuilder.AddDeclarativeSecurity (de.Key, de.Value);
1820 #endif
1824 block = null;
1827 protected override MemberSpec FindBaseMember (out MemberSpec bestCandidate, ref bool overrides)
1829 // Is never override
1830 bestCandidate = null;
1831 return null;
1834 public override string GetCallerMemberName ()
1836 return IsStatic ? TypeConstructorName : ConstructorName;
1839 public override string GetSignatureForDocumentation ()
1841 return Parent.GetSignatureForDocumentation () + ".#ctor" + parameters.GetSignatureForDocumentation ();
1844 public override string GetSignatureForError()
1846 return base.GetSignatureForError () + parameters.GetSignatureForError ();
1849 public override string[] ValidAttributeTargets {
1850 get {
1851 return attribute_targets;
1855 protected override bool VerifyClsCompliance ()
1857 if (!base.VerifyClsCompliance () || !IsExposedFromAssembly ()) {
1858 return false;
1861 if (!parameters.IsEmpty && Parent.Definition.IsAttribute) {
1862 foreach (TypeSpec param in parameters.Types) {
1863 if (param.IsArray) {
1864 return true;
1869 has_compliant_args = true;
1870 return true;
1873 public override void WriteDebugSymbol (MonoSymbolFile file)
1875 if (debug_builder == null)
1876 return;
1878 var token = ConstructorBuilder.GetToken ();
1879 int t = token.Token;
1880 #if STATIC
1881 if (ModuleBuilder.IsPseudoToken (t))
1882 t = Module.Builder.ResolvePseudoToken (t);
1883 #endif
1885 debug_builder.DefineMethod (file, t);
1888 #region IMethodData Members
1890 public MemberName MethodName {
1891 get {
1892 return MemberName;
1896 public TypeSpec ReturnType {
1897 get {
1898 return MemberType;
1902 EmitContext IMethodData.CreateEmitContext (ILGenerator ig, SourceMethodBuilder sourceMethod)
1904 throw new NotImplementedException ();
1907 #endregion
1910 /// <summary>
1911 /// Interface for MethodData class. Holds links to parent members to avoid member duplication.
1912 /// </summary>
1913 public interface IMethodData : IMemberContext
1915 CallingConventions CallingConventions { get; }
1916 Location Location { get; }
1917 MemberName MethodName { get; }
1918 TypeSpec ReturnType { get; }
1919 ParametersCompiled ParameterInfo { get; }
1920 MethodSpec Spec { get; }
1921 bool IsAccessor { get; }
1923 Attributes OptAttributes { get; }
1924 ToplevelBlock Block { get; set; }
1926 EmitContext CreateEmitContext (ILGenerator ig, SourceMethodBuilder sourceMethod);
1930 // Encapsulates most of the Method's state
1932 public class MethodData
1934 public readonly IMethodData method;
1937 // Are we implementing an interface ?
1939 public MethodSpec implementing;
1942 // Protected data.
1944 protected InterfaceMemberBase member;
1945 protected Modifiers modifiers;
1946 protected MethodAttributes flags;
1947 protected TypeSpec declaring_type;
1948 protected MethodSpec parent_method;
1949 SourceMethodBuilder debug_builder;
1950 string full_name;
1952 MethodBuilder builder;
1953 public MethodBuilder MethodBuilder {
1954 get {
1955 return builder;
1959 public TypeSpec DeclaringType {
1960 get {
1961 return declaring_type;
1965 public string MetadataName {
1966 get {
1967 return full_name;
1971 public MethodData (InterfaceMemberBase member,
1972 Modifiers modifiers, MethodAttributes flags, IMethodData method)
1974 this.member = member;
1975 this.modifiers = modifiers;
1976 this.flags = flags;
1978 this.method = method;
1981 public MethodData (InterfaceMemberBase member,
1982 Modifiers modifiers, MethodAttributes flags,
1983 IMethodData method,
1984 MethodSpec parent_method)
1985 : this (member, modifiers, flags, method)
1987 this.parent_method = parent_method;
1990 public bool Define (TypeDefinition container, string method_full_name)
1992 PendingImplementation pending = container.PendingImplementations;
1993 MethodSpec ambig_iface_method;
1994 bool optional = false;
1996 if (pending != null) {
1997 implementing = pending.IsInterfaceMethod (method.MethodName, member.InterfaceType, this, out ambig_iface_method, ref optional);
1999 if (member.InterfaceType != null) {
2000 if (implementing == null) {
2001 if (member is PropertyBase) {
2002 container.Compiler.Report.Error (550, method.Location,
2003 "`{0}' is an accessor not found in interface member `{1}{2}'",
2004 method.GetSignatureForError (), member.InterfaceType.GetSignatureForError (),
2005 member.GetSignatureForError ().Substring (member.GetSignatureForError ().LastIndexOf ('.')));
2007 } else {
2008 container.Compiler.Report.Error (539, method.Location,
2009 "`{0}.{1}' in explicit interface declaration is not a member of interface",
2010 member.InterfaceType.GetSignatureForError (), member.ShortName);
2012 return false;
2014 if (implementing.IsAccessor && !method.IsAccessor) {
2015 container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
2016 container.Compiler.Report.Error (683, method.Location,
2017 "`{0}' explicit method implementation cannot implement `{1}' because it is an accessor",
2018 member.GetSignatureForError (), implementing.GetSignatureForError ());
2019 return false;
2021 } else {
2022 if (implementing != null && !optional) {
2023 if (!method.IsAccessor) {
2024 if (implementing.IsAccessor) {
2025 container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
2026 container.Compiler.Report.Error (470, method.Location,
2027 "Method `{0}' cannot implement interface accessor `{1}'",
2028 method.GetSignatureForError (), TypeManager.CSharpSignature (implementing));
2030 } else if (implementing.DeclaringType.IsInterface) {
2031 if (!implementing.IsAccessor) {
2032 container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
2033 container.Compiler.Report.Error (686, method.Location,
2034 "Accessor `{0}' cannot implement interface member `{1}' for type `{2}'. Use an explicit interface implementation",
2035 method.GetSignatureForError (), TypeManager.CSharpSignature (implementing), container.GetSignatureForError ());
2036 } else {
2037 PropertyBase.PropertyMethod pm = method as PropertyBase.PropertyMethod;
2038 if (pm != null && pm.HasCustomAccessModifier && (pm.ModFlags & Modifiers.PUBLIC) == 0) {
2039 container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
2040 container.Compiler.Report.Error (277, method.Location,
2041 "Accessor `{0}' must be declared public to implement interface member `{1}'",
2042 method.GetSignatureForError (), implementing.GetSignatureForError ());
2048 } else {
2049 ambig_iface_method = null;
2053 // For implicit implementations, make sure we are public, for
2054 // explicit implementations, make sure we are private.
2056 if (implementing != null){
2057 if (member.IsExplicitImpl) {
2058 if (method.ParameterInfo.HasParams && !implementing.Parameters.HasParams) {
2059 container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
2060 container.Compiler.Report.Error (466, method.Location,
2061 "`{0}': the explicit interface implementation cannot introduce the params modifier",
2062 method.GetSignatureForError ());
2065 if (ambig_iface_method != null) {
2066 container.Compiler.Report.SymbolRelatedToPreviousError (ambig_iface_method);
2067 container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
2068 container.Compiler.Report.Warning (473, 2, method.Location,
2069 "Explicit interface implementation `{0}' matches more than one interface member. Consider using a non-explicit implementation instead",
2070 method.GetSignatureForError ());
2072 } else {
2074 // Setting implementin to null inside this block will trigger a more
2075 // verbose error reporting for missing interface implementations
2077 if (implementing.DeclaringType.IsInterface) {
2079 // If this is an interface method implementation,
2080 // check for public accessibility
2082 if ((flags & MethodAttributes.MemberAccessMask) != MethodAttributes.Public) {
2083 implementing = null;
2084 } else if (optional && (container.Interfaces == null || !container.Definition.Interfaces.Contains (implementing.DeclaringType))) {
2086 // We are not implementing interface when base class already implemented it
2088 implementing = null;
2090 } else if ((flags & MethodAttributes.MemberAccessMask) == MethodAttributes.Private) {
2091 // We may never be private.
2092 implementing = null;
2094 } else if ((modifiers & Modifiers.OVERRIDE) == 0) {
2096 // We may be protected if we're overriding something.
2098 implementing = null;
2103 // Static is not allowed
2105 if ((modifiers & Modifiers.STATIC) != 0){
2106 implementing = null;
2111 // If implementing is still valid, set flags
2113 if (implementing != null){
2115 // When implementing interface methods, set NewSlot
2116 // unless, we are overwriting a method.
2118 if ((modifiers & Modifiers.OVERRIDE) == 0 && implementing.DeclaringType.IsInterface) {
2119 flags |= MethodAttributes.NewSlot;
2122 flags |= MethodAttributes.Virtual | MethodAttributes.HideBySig;
2124 // Set Final unless we're virtual, abstract or already overriding a method.
2125 if ((modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE)) == 0)
2126 flags |= MethodAttributes.Final;
2129 // clear the pending implementation flag (requires explicit methods to be defined first)
2131 pending.ImplementMethod (method.MethodName,
2132 member.InterfaceType, this, member.IsExplicitImpl, out ambig_iface_method, ref optional);
2135 // Update indexer accessor name to match implementing abstract accessor
2137 if (!implementing.DeclaringType.IsInterface && !member.IsExplicitImpl && implementing.IsAccessor)
2138 method_full_name = implementing.MemberDefinition.Name;
2141 full_name = method_full_name;
2142 declaring_type = container.Definition;
2144 return true;
2147 void DefineOverride (TypeDefinition container)
2149 if (implementing == null)
2150 return;
2152 if (!member.IsExplicitImpl)
2153 return;
2155 container.TypeBuilder.DefineMethodOverride (builder, (MethodInfo) implementing.GetMetaInfo ());
2159 // Creates partial MethodBuilder for the method when has generic parameters used
2160 // as arguments or return type
2162 public MethodBuilder DefineMethodBuilder (TypeDefinition container)
2164 if (builder != null)
2165 throw new InternalErrorException ();
2167 builder = container.TypeBuilder.DefineMethod (full_name, flags, method.CallingConventions);
2168 return builder;
2172 // Creates full MethodBuilder for the method
2174 public MethodBuilder DefineMethodBuilder (TypeDefinition container, ParametersCompiled param)
2176 DefineMethodBuilder (container);
2177 builder.SetReturnType (method.ReturnType.GetMetaInfo ());
2178 builder.SetParameters (param.GetMetaInfo ());
2179 return builder;
2183 // Emits the code
2185 public void Emit (TypeDefinition parent)
2187 DefineOverride (parent);
2189 method.ParameterInfo.ApplyAttributes (method, MethodBuilder);
2191 ToplevelBlock block = method.Block;
2192 if (block != null) {
2193 BlockContext bc = new BlockContext (method, block, method.ReturnType);
2194 if (block.Resolve (bc, method)) {
2195 debug_builder = member.Parent.CreateMethodSymbolEntry ();
2196 EmitContext ec = method.CreateEmitContext (MethodBuilder.GetILGenerator (), debug_builder);
2198 block.Emit (ec);
2203 public void WriteDebugSymbol (MonoSymbolFile file)
2205 if (debug_builder == null)
2206 return;
2208 var token = builder.GetToken ();
2209 int t = token.Token;
2210 #if STATIC
2211 if (ModuleBuilder.IsPseudoToken (t))
2212 t = member.Module.Builder.ResolvePseudoToken (t);
2213 #endif
2215 debug_builder.DefineMethod (file, t);
2219 public class Destructor : MethodOrOperator
2221 const Modifiers AllowedModifiers =
2222 Modifiers.UNSAFE |
2223 Modifiers.EXTERN;
2225 static readonly string[] attribute_targets = new string [] { "method" };
2227 public static readonly string MetadataName = "Finalize";
2229 public Destructor (TypeDefinition parent, Modifiers mod, ParametersCompiled parameters, Attributes attrs, Location l)
2230 : base (parent, null, mod, AllowedModifiers, new MemberName (MetadataName, l), attrs, parameters)
2232 ModFlags &= ~Modifiers.PRIVATE;
2233 ModFlags |= Modifiers.PROTECTED | Modifiers.OVERRIDE;
2236 public override void Accept (StructuralVisitor visitor)
2238 visitor.Visit (this);
2241 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
2243 if (a.Type == pa.Conditional) {
2244 Error_ConditionalAttributeIsNotValid ();
2245 return;
2248 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
2251 protected override bool CheckBase ()
2253 if ((caching_flags & Flags.MethodOverloadsExist) != 0)
2254 CheckForDuplications ();
2256 // Don't check base, destructors have special syntax
2257 return true;
2260 public override bool Define ()
2262 base.Define ();
2264 if (Compiler.Settings.WriteMetadataOnly)
2265 block = null;
2267 return true;
2270 public override void Emit()
2272 var base_type = Parent.PartialContainer.BaseType;
2273 if (base_type != null && Block != null) {
2274 var base_dtor = MemberCache.FindMember (base_type,
2275 new MemberFilter (MetadataName, 0, MemberKind.Destructor, null, null), BindingRestriction.InstanceOnly) as MethodSpec;
2277 if (base_dtor == null)
2278 throw new NotImplementedException ();
2280 MethodGroupExpr method_expr = MethodGroupExpr.CreatePredefined (base_dtor, base_type, Location);
2281 method_expr.InstanceExpression = new BaseThis (base_type, Location);
2283 var try_block = new ExplicitBlock (block, block.StartLocation, block.EndLocation) {
2284 IsCompilerGenerated = true
2286 var finaly_block = new ExplicitBlock (block, Location, Location) {
2287 IsCompilerGenerated = true
2291 // 0-size arguments to avoid CS0250 error
2292 // TODO: Should use AddScopeStatement or something else which emits correct
2293 // debugger scope
2295 finaly_block.AddStatement (new StatementExpression (new Invocation (method_expr, new Arguments (0)), Location.Null));
2297 var tf = new TryFinally (try_block, finaly_block, Location);
2298 block.WrapIntoDestructor (tf, try_block);
2301 base.Emit ();
2304 public override string GetSignatureForError ()
2306 return Parent.GetSignatureForError () + ".~" + Parent.MemberName.Name + "()";
2309 protected override bool ResolveMemberType ()
2311 member_type = Compiler.BuiltinTypes.Void;
2312 return true;
2315 public override string[] ValidAttributeTargets {
2316 get {
2317 return attribute_targets;
2322 // Ooouh Martin, templates are missing here.
2323 // When it will be possible move here a lot of child code and template method type.
2324 public abstract class AbstractPropertyEventMethod : MemberCore, IMethodData, IMethodDefinition {
2325 protected MethodData method_data;
2326 protected ToplevelBlock block;
2327 protected SecurityType declarative_security;
2329 protected readonly string prefix;
2331 ReturnParameter return_attributes;
2333 protected AbstractPropertyEventMethod (InterfaceMemberBase member, string prefix, Attributes attrs, Location loc)
2334 : base (member.Parent, SetupName (prefix, member, loc), attrs)
2336 this.prefix = prefix;
2339 static MemberName SetupName (string prefix, InterfaceMemberBase member, Location loc)
2341 return new MemberName (member.MemberName.Left, prefix + member.ShortName, member.MemberName.ExplicitInterface, loc);
2344 public void UpdateName (InterfaceMemberBase member)
2346 SetMemberName (SetupName (prefix, member, Location));
2349 #region IMethodData Members
2351 public ToplevelBlock Block {
2352 get {
2353 return block;
2356 set {
2357 block = value;
2361 public CallingConventions CallingConventions {
2362 get {
2363 return CallingConventions.Standard;
2367 public EmitContext CreateEmitContext (ILGenerator ig, SourceMethodBuilder sourceMethod)
2369 return new EmitContext (this, ig, ReturnType, sourceMethod);
2372 public bool IsAccessor {
2373 get {
2374 return true;
2378 public MemberName MethodName {
2379 get {
2380 return MemberName;
2384 public TypeSpec[] ParameterTypes {
2385 get {
2386 return ParameterInfo.Types;
2390 MethodBase IMethodDefinition.Metadata {
2391 get {
2392 return method_data.MethodBuilder;
2396 public abstract ParametersCompiled ParameterInfo { get ; }
2397 public abstract TypeSpec ReturnType { get; }
2399 #endregion
2401 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
2403 if (a.Type == pa.CLSCompliant || a.Type == pa.Obsolete || a.Type == pa.Conditional) {
2404 Report.Error (1667, a.Location,
2405 "Attribute `{0}' is not valid on property or event accessors. It is valid on `{1}' declarations only",
2406 a.Type.GetSignatureForError (), a.GetValidTargets ());
2407 return;
2410 if (a.IsValidSecurityAttribute ()) {
2411 a.ExtractSecurityPermissionSet (ctor, ref declarative_security);
2412 return;
2415 if (a.Target == AttributeTargets.Method) {
2416 method_data.MethodBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
2417 return;
2420 if (a.Target == AttributeTargets.ReturnValue) {
2421 if (return_attributes == null)
2422 return_attributes = new ReturnParameter (this, method_data.MethodBuilder, Location);
2424 return_attributes.ApplyAttributeBuilder (a, ctor, cdata, pa);
2425 return;
2428 ApplyToExtraTarget (a, ctor, cdata, pa);
2431 protected virtual void ApplyToExtraTarget (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
2433 throw new NotSupportedException ("You forgot to define special attribute target handling");
2436 // It is not supported for the accessors
2437 public sealed override bool Define()
2439 throw new NotSupportedException ();
2442 public virtual void Emit (TypeDefinition parent)
2444 method_data.Emit (parent);
2446 if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
2447 Module.PredefinedAttributes.CompilerGenerated.EmitAttribute (method_data.MethodBuilder);
2448 if (((ModFlags & Modifiers.DEBUGGER_HIDDEN) != 0))
2449 Module.PredefinedAttributes.DebuggerHidden.EmitAttribute (method_data.MethodBuilder);
2451 if (ReturnType.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2452 return_attributes = new ReturnParameter (this, method_data.MethodBuilder, Location);
2453 Module.PredefinedAttributes.Dynamic.EmitAttribute (return_attributes.Builder);
2454 } else if (ReturnType.HasDynamicElement) {
2455 return_attributes = new ReturnParameter (this, method_data.MethodBuilder, Location);
2456 Module.PredefinedAttributes.Dynamic.EmitAttribute (return_attributes.Builder, ReturnType, Location);
2459 if (OptAttributes != null)
2460 OptAttributes.Emit ();
2462 if (declarative_security != null) {
2463 foreach (var de in declarative_security) {
2464 #if STATIC
2465 method_data.MethodBuilder.__AddDeclarativeSecurity (de);
2466 #else
2467 method_data.MethodBuilder.AddDeclarativeSecurity (de.Key, de.Value);
2468 #endif
2472 block = null;
2475 public override bool EnableOverloadChecks (MemberCore overload)
2477 if (overload is MethodCore) {
2478 caching_flags |= Flags.MethodOverloadsExist;
2479 return true;
2482 // This can only happen with indexers and it will
2483 // be catched as indexer difference
2484 if (overload is AbstractPropertyEventMethod)
2485 return true;
2487 return false;
2490 public override string GetCallerMemberName ()
2492 return base.GetCallerMemberName ().Substring (prefix.Length);
2495 public override string GetSignatureForDocumentation ()
2497 // should not be called
2498 throw new NotSupportedException ();
2501 public override bool IsClsComplianceRequired()
2503 return false;
2506 public void PrepareEmit ()
2508 method_data.DefineMethodBuilder (Parent.PartialContainer, ParameterInfo);
2511 public override void WriteDebugSymbol (MonoSymbolFile file)
2513 if (method_data != null)
2514 method_data.WriteDebugSymbol (file);
2517 public MethodSpec Spec { get; protected set; }
2520 // Represents header string for documentation comment.
2522 public override string DocCommentHeader {
2523 get { throw new InvalidOperationException ("Unexpected attempt to get doc comment from " + this.GetType () + "."); }
2527 public class Operator : MethodOrOperator {
2529 const Modifiers AllowedModifiers =
2530 Modifiers.PUBLIC |
2531 Modifiers.UNSAFE |
2532 Modifiers.EXTERN |
2533 Modifiers.STATIC;
2535 public enum OpType : byte {
2537 // Unary operators
2538 LogicalNot,
2539 OnesComplement,
2540 Increment,
2541 Decrement,
2542 True,
2543 False,
2545 // Unary and Binary operators
2546 Addition,
2547 Subtraction,
2549 UnaryPlus,
2550 UnaryNegation,
2552 // Binary operators
2553 Multiply,
2554 Division,
2555 Modulus,
2556 BitwiseAnd,
2557 BitwiseOr,
2558 ExclusiveOr,
2559 LeftShift,
2560 RightShift,
2561 Equality,
2562 Inequality,
2563 GreaterThan,
2564 LessThan,
2565 GreaterThanOrEqual,
2566 LessThanOrEqual,
2568 // Implicit and Explicit
2569 Implicit,
2570 Explicit,
2572 // Pattern matching
2575 // Just because of enum
2579 public readonly OpType OperatorType;
2581 static readonly string [] [] names;
2583 static Operator ()
2585 names = new string[(int)OpType.TOP][];
2586 names [(int) OpType.LogicalNot] = new string [] { "!", "op_LogicalNot" };
2587 names [(int) OpType.OnesComplement] = new string [] { "~", "op_OnesComplement" };
2588 names [(int) OpType.Increment] = new string [] { "++", "op_Increment" };
2589 names [(int) OpType.Decrement] = new string [] { "--", "op_Decrement" };
2590 names [(int) OpType.True] = new string [] { "true", "op_True" };
2591 names [(int) OpType.False] = new string [] { "false", "op_False" };
2592 names [(int) OpType.Addition] = new string [] { "+", "op_Addition" };
2593 names [(int) OpType.Subtraction] = new string [] { "-", "op_Subtraction" };
2594 names [(int) OpType.UnaryPlus] = new string [] { "+", "op_UnaryPlus" };
2595 names [(int) OpType.UnaryNegation] = new string [] { "-", "op_UnaryNegation" };
2596 names [(int) OpType.Multiply] = new string [] { "*", "op_Multiply" };
2597 names [(int) OpType.Division] = new string [] { "/", "op_Division" };
2598 names [(int) OpType.Modulus] = new string [] { "%", "op_Modulus" };
2599 names [(int) OpType.BitwiseAnd] = new string [] { "&", "op_BitwiseAnd" };
2600 names [(int) OpType.BitwiseOr] = new string [] { "|", "op_BitwiseOr" };
2601 names [(int) OpType.ExclusiveOr] = new string [] { "^", "op_ExclusiveOr" };
2602 names [(int) OpType.LeftShift] = new string [] { "<<", "op_LeftShift" };
2603 names [(int) OpType.RightShift] = new string [] { ">>", "op_RightShift" };
2604 names [(int) OpType.Equality] = new string [] { "==", "op_Equality" };
2605 names [(int) OpType.Inequality] = new string [] { "!=", "op_Inequality" };
2606 names [(int) OpType.GreaterThan] = new string [] { ">", "op_GreaterThan" };
2607 names [(int) OpType.LessThan] = new string [] { "<", "op_LessThan" };
2608 names [(int) OpType.GreaterThanOrEqual] = new string [] { ">=", "op_GreaterThanOrEqual" };
2609 names [(int) OpType.LessThanOrEqual] = new string [] { "<=", "op_LessThanOrEqual" };
2610 names [(int) OpType.Implicit] = new string [] { "implicit", "op_Implicit" };
2611 names [(int) OpType.Explicit] = new string [] { "explicit", "op_Explicit" };
2612 names [(int) OpType.Is] = new string[] { "is", "op_Is" };
2615 public Operator (TypeDefinition parent, OpType type, FullNamedExpression ret_type, Modifiers mod_flags, ParametersCompiled parameters,
2616 ToplevelBlock block, Attributes attrs, Location loc)
2617 : base (parent, ret_type, mod_flags, AllowedModifiers, new MemberName (GetMetadataName (type), loc), attrs, parameters)
2619 OperatorType = type;
2620 Block = block;
2623 public override void Accept (StructuralVisitor visitor)
2625 visitor.Visit (this);
2628 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
2630 if (a.Type == pa.Conditional) {
2631 Error_ConditionalAttributeIsNotValid ();
2632 return;
2635 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
2638 public override bool Define ()
2640 const Modifiers RequiredModifiers = Modifiers.PUBLIC | Modifiers.STATIC;
2641 if ((ModFlags & RequiredModifiers) != RequiredModifiers){
2642 Report.Error (558, Location, "User-defined operator `{0}' must be declared static and public", GetSignatureForError ());
2645 if (!base.Define ())
2646 return false;
2648 if (block != null) {
2649 if (block.IsIterator) {
2651 // Current method is turned into automatically generated
2652 // wrapper which creates an instance of iterator
2654 Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags);
2655 ModFlags |= Modifiers.DEBUGGER_HIDDEN;
2658 if (Compiler.Settings.WriteMetadataOnly)
2659 block = null;
2662 // imlicit and explicit operator of same types are not allowed
2663 if (OperatorType == OpType.Explicit)
2664 Parent.MemberCache.CheckExistingMembersOverloads (this, GetMetadataName (OpType.Implicit), parameters);
2665 else if (OperatorType == OpType.Implicit)
2666 Parent.MemberCache.CheckExistingMembersOverloads (this, GetMetadataName (OpType.Explicit), parameters);
2668 TypeSpec declaring_type = Parent.PartialContainer.CurrentType;
2669 TypeSpec return_type = MemberType;
2670 TypeSpec first_arg_type = ParameterTypes [0];
2672 TypeSpec first_arg_type_unwrap = first_arg_type;
2673 if (first_arg_type.IsNullableType)
2674 first_arg_type_unwrap = Nullable.NullableInfo.GetUnderlyingType (first_arg_type);
2676 TypeSpec return_type_unwrap = return_type;
2677 if (return_type.IsNullableType)
2678 return_type_unwrap = Nullable.NullableInfo.GetUnderlyingType (return_type);
2681 // Rules for conversion operators
2683 if (OperatorType == OpType.Implicit || OperatorType == OpType.Explicit) {
2684 if (first_arg_type_unwrap == return_type_unwrap && first_arg_type_unwrap == declaring_type) {
2685 Report.Error (555, Location,
2686 "User-defined operator cannot take an object of the enclosing type and convert to an object of the enclosing type");
2687 return false;
2690 TypeSpec conv_type;
2691 if (declaring_type == return_type || declaring_type == return_type_unwrap) {
2692 conv_type = first_arg_type;
2693 } else if (declaring_type == first_arg_type || declaring_type == first_arg_type_unwrap) {
2694 conv_type = return_type;
2695 } else {
2696 Report.Error (556, Location,
2697 "User-defined conversion must convert to or from the enclosing type");
2698 return false;
2701 if (conv_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2702 Report.Error (1964, Location,
2703 "User-defined conversion `{0}' cannot convert to or from the dynamic type",
2704 GetSignatureForError ());
2706 return false;
2709 if (conv_type.IsInterface) {
2710 Report.Error (552, Location, "User-defined conversion `{0}' cannot convert to or from an interface type",
2711 GetSignatureForError ());
2712 return false;
2715 if (conv_type.IsClass) {
2716 if (TypeSpec.IsBaseClass (declaring_type, conv_type, true)) {
2717 Report.Error (553, Location, "User-defined conversion `{0}' cannot convert to or from a base class",
2718 GetSignatureForError ());
2719 return false;
2722 if (TypeSpec.IsBaseClass (conv_type, declaring_type, false)) {
2723 Report.Error (554, Location, "User-defined conversion `{0}' cannot convert to or from a derived class",
2724 GetSignatureForError ());
2725 return false;
2728 } else if (OperatorType == OpType.LeftShift || OperatorType == OpType.RightShift) {
2729 if (first_arg_type != declaring_type || parameters.Types[1].BuiltinType != BuiltinTypeSpec.Type.Int) {
2730 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");
2731 return false;
2733 } else if (parameters.Count == 1) {
2734 // Checks for Unary operators
2736 if (OperatorType == OpType.Increment || OperatorType == OpType.Decrement) {
2737 if (return_type != declaring_type && !TypeSpec.IsBaseClass (return_type, declaring_type, false)) {
2738 Report.Error (448, Location,
2739 "The return type for ++ or -- operator must be the containing type or derived from the containing type");
2740 return false;
2742 if (first_arg_type != declaring_type) {
2743 Report.Error (
2744 559, Location, "The parameter type for ++ or -- operator must be the containing type");
2745 return false;
2749 if (first_arg_type_unwrap != declaring_type) {
2750 Report.Error (562, Location,
2751 "The parameter type of a unary operator must be the containing type");
2752 return false;
2755 if (OperatorType == OpType.True || OperatorType == OpType.False) {
2756 if (return_type.BuiltinType != BuiltinTypeSpec.Type.Bool) {
2757 Report.Error (
2758 215, Location,
2759 "The return type of operator True or False " +
2760 "must be bool");
2761 return false;
2765 } else if (first_arg_type_unwrap != declaring_type) {
2766 // Checks for Binary operators
2768 var second_arg_type = ParameterTypes[1];
2769 if (second_arg_type.IsNullableType)
2770 second_arg_type = Nullable.NullableInfo.GetUnderlyingType (second_arg_type);
2772 if (second_arg_type != declaring_type) {
2773 Report.Error (563, Location,
2774 "One of the parameters of a binary operator must be the containing type");
2775 return false;
2779 return true;
2782 protected override bool ResolveMemberType ()
2784 if (!base.ResolveMemberType ())
2785 return false;
2787 flags |= MethodAttributes.SpecialName | MethodAttributes.HideBySig;
2788 return true;
2791 protected override MemberSpec FindBaseMember (out MemberSpec bestCandidate, ref bool overrides)
2793 // Operator cannot be override
2794 bestCandidate = null;
2795 return null;
2798 public static string GetName (OpType ot)
2800 return names [(int) ot] [0];
2803 public static string GetName (string metadata_name)
2805 for (int i = 0; i < names.Length; ++i) {
2806 if (names [i] [1] == metadata_name)
2807 return names [i] [0];
2809 return null;
2812 public static string GetMetadataName (OpType ot)
2814 return names [(int) ot] [1];
2817 public static string GetMetadataName (string name)
2819 for (int i = 0; i < names.Length; ++i) {
2820 if (names [i] [0] == name)
2821 return names [i] [1];
2823 return null;
2826 public static OpType? GetType (string metadata_name)
2828 for (int i = 0; i < names.Length; ++i) {
2829 if (names[i][1] == metadata_name)
2830 return (OpType) i;
2833 return null;
2836 public OpType GetMatchingOperator ()
2838 switch (OperatorType) {
2839 case OpType.Equality:
2840 return OpType.Inequality;
2841 case OpType.Inequality:
2842 return OpType.Equality;
2843 case OpType.True:
2844 return OpType.False;
2845 case OpType.False:
2846 return OpType.True;
2847 case OpType.GreaterThan:
2848 return OpType.LessThan;
2849 case OpType.LessThan:
2850 return OpType.GreaterThan;
2851 case OpType.GreaterThanOrEqual:
2852 return OpType.LessThanOrEqual;
2853 case OpType.LessThanOrEqual:
2854 return OpType.GreaterThanOrEqual;
2855 default:
2856 return OpType.TOP;
2860 public override string GetSignatureForDocumentation ()
2862 string s = base.GetSignatureForDocumentation ();
2863 if (OperatorType == OpType.Implicit || OperatorType == OpType.Explicit) {
2864 s = s + "~" + ReturnType.GetSignatureForDocumentation ();
2867 return s;
2870 public override string GetSignatureForError ()
2872 StringBuilder sb = new StringBuilder ();
2873 if (OperatorType == OpType.Implicit || OperatorType == OpType.Explicit) {
2874 sb.AppendFormat ("{0}.{1} operator {2}",
2875 Parent.GetSignatureForError (), GetName (OperatorType),
2876 member_type == null ? type_expr.GetSignatureForError () : member_type.GetSignatureForError ());
2878 else {
2879 sb.AppendFormat ("{0}.operator {1}", Parent.GetSignatureForError (), GetName (OperatorType));
2882 sb.Append (parameters.GetSignatureForError ());
2883 return sb.ToString ();